From Accounts to Constant Product

账户体系恒定乘积
一页读懂 EVM 与 AMM

EVM 上的一切交互,都可以拆成两句话:只有 EOA 能发起交易,合约只能被动响应;而 DEX 里的价格,全由 x·y=k 这条双曲线决定。下面把账户、合约生命周期、权限、调用链路与 XYK 模型串成一条完整脉络——核心概念可动手实验。

2 类账户 5 步生命周期 x·y=k 可交互模拟 msg.sender vs tx.origin 7 个高频误区
01

两类账户 · 一切交互的根基

EVM 公链(ETH / BSC / Polygon / Arbitrum…)只存在两种账户,没有第三种。所有链上行为——部署、转账、调用、Swap——全部基于这两者实现。

🔑
EXTERNALLY OWNED ACCOUNT

EOA · 外部拥有账户

由私钥 / 公钥加密生成的人类可控账户,就是你 MetaMask 里那个地址。

  • 唯一能主动发起链上交易的账户——所有操作的源头
  • 拥有私钥,可签名交易、支付 Gas
  • 自带 Nonce(交易序号,防重放、定顺序)
  • 可持有链原生代币(ETH / BNB / MATIC)
  • 无代码、无合约逻辑、无持久化存储
📜
CONTRACT ACCOUNT

CA · 合约账户

由 EOA 的部署交易生成的独立链上程序,一段跑在链上的代码。

  • 无私钥,无法主动发起任何交易,只能被动被调用
  • 拥有独立 Bytecode(代码)+ 独立 Storage(持久存储)
  • 可持有原生代币,以及所有 ERC-20 代币
  • 无自主意识、无决策能力,仅执行预设代码逻辑
  • 被调用时,代码在每个节点的 EVM 里确定性地执行
EOA交易发起者(唯一入口)
CA逻辑执行者(被动响应)
铁律所有链上操作,源头一定是 EOA

↗ 延伸 · Pectra 之后的现代补充

「EOA 无代码」是经典结论,但 2025 年 5 月的 Pectra 升级(EIP-7702)允许一个 EOA 临时「挂载」一段合约代码,从而获得账户抽象能力:批量操作、Gas 代付、社交恢复等,让钱包用起来像智能合约。关键在于——即便如此,发起交易的源头仍是 EOA 的私钥签名,「只有 EOA 能发起交易」这条铁律没有被打破。

02

合约生命周期 · 源码到调用

一个合约从 Solidity 源码到能被调用,要走完编译、部署、初始化三关。点下面的标签逐步查看每一关内部发生了什么。

↗ 延伸 · 合约地址是怎么算出来的

部署时链生成的 CA 地址并非随机,而是可计算的。普通部署用 CREATE:地址 = keccak256(rlp(部署者地址, nonce)) 取后 20 字节——所以同一账户第 N 次部署的地址是确定的。另一种 CREATE2 额外加一个盐值 salt,让地址在部署之前就能完全算出,很多协议用它做「反事实地址」(先给用户地址、之后再真正部署)。

03

权限的本质 · 默认人人平等

最反直觉、也最重要的一点:EVM 底层不存在合约归属和默认管理员。部署完成后,合约就是个独立账户,和部署者没有任何底层绑定。

DEFAULT

底层无天然归属

  • 合约部署后是独立账户,和部署者 EOA 无底层绑定
  • 不写权限代码 = 全网所有 EOA 完全平等
  • 唯一差异:初始代币铸在部署者钱包(资产差异 ≠ 权限差异
PRIVILEGE · 1

管理员权限

  • 手动在 Storage 存一个 owner 地址
  • require(msg.sender==owner) 限制专属操作
  • 没有这行代码,就没有管理员——特权是人为写出来的
PRIVILEGE · 2

税费 / 分润逻辑

  • 代码内置交易抽成(如每笔 swap 抽 x%)
  • 自动把抽成转给部署者或指定地址
  • 同样是代码定义,链本身不会替谁收钱
04

调用链路 · 谁在调用谁

新手最大误区:以为调用别人部署的合约,要「经过」部署者。其实链路是直的。切换下面两种场景,看 msg.sendertx.origin 在每一跳如何取值。

⚠ 安全延伸 · 为什么不能用 tx.origin 做权限校验

msg.sender直接调用者tx.origin整笔交易最源头的 EOA(永远是钱包,不会是合约)。若某钱包合约用 require(tx.origin==owner) 鉴权,攻击者可诱导 owner 去调用一个恶意合约 M,M 再回调该钱包——此时 tx.origin 仍是 owner,鉴权被绕过。正确做法是用 msg.sender,这也是 tx.origin 极少用于授权的原因。

05

XYK 恒定乘积模型 · 亲手做一笔 Swap

DEX 池子的全部数学,浓缩在一条双曲线 x·y=k 里。下面是一个真实运行的模拟器:拖动滑块卖出代币 X,看曲线上的点如何滑动、价格如何变化、滑点从哪来;再用按钮加减流动性,看池子深度(k)如何改变。

x · y = k  瞬时价格 P = y / x

X 储备 → ↑ Y
初始 X 储备
初始 Y 储备
获得 Y
0
成交均价 (Y/X)
兑换后新价格
1.0000
滑点
0.00%
k(兑换前)
k(兑换后)
手续费 0.3%(Uniswap V2 真实模型,997/1000)

提示:Swap 只改变比例、k 不变;加/减流动性等比缩放、只改变深度(k),价格不变。

Swap 兑换

  • 资产此消彼长(x↑y↓ 或 x↓y↑)
  • 无手续费时 k 绝对恒定
  • 价格随供需自动涨跌,产生滑点
  • 只改变比例,不改变池子总体量

LP 增 / 减流动性

  • 添加:x、y 等比同步增大 → k 变大 → 池子加深、滑点降
  • 移除:x、y 等比同步减小 → k 变小 → 池子变浅、滑点升
  • 价格不变,仅改变池子深度

池子深度本质

  • 池子深度 = k 值大小
  • k 越大:流动性越深,大额交易滑点越小
  • k 越小:流动性浅,小额也会剧烈「插针」
  • 滑点只和 k 有关,和代币总发行量无关

↗ 延伸 · 真实世界的细节

手续费让 k 微增:打开上面的 0.3% 开关,你会发现每次 swap 后 k 略微变大——因为手续费被留在了池里,正是 LP 的收益来源。  滑点公式:无手续费时滑点 ≈ Δx /(x+Δx),只取决于交易量相对储备的比例,这就是「大池子滑点小」的数学原因。  初始化:空 Pair 池 reserve=0、k=0 无法交易,必须由 LP 首次双币注入才能激活;XYK 必须双资产,无法单币建池。  无常损失:当外部价格变动时,LP 按 x·y=k 被动调仓,导致其持仓价值低于「单纯拿着两种币不动」,这就是无常损失。

06

EVM vs Solana · 同一套数学,两种工程

跨链最常见的误解是以为「模型不同」。其实 XYK 数学模型通用不变,两条链的差别只在逻辑与存储如何组织

EVM(ETH / BSC)

逻辑 + 存储绑定:一个池子 = 一个独立的 Pair 合约
Factory 工厂批量部署新合约,生成交易对
每个 Pair 独立存储 x、y、k,完全隔离
新增一个池子 = 部署一段新代码(新 CA)

Solana

逻辑与存储分离:一套 AMM 程序全网复用
创建池子仅新建存储账户,不部署新代码
所有池子共享同一份程序逻辑
账户模型是「程序 + 数据账户」的分离设计

XYK 数学模型通用不变,仅工程实现不同。

07

高频误区 · 100% 避坑清单

这七条几乎覆盖新手 99% 的误解,逐条对照纠正。

08

极简记忆口诀

把整份全景图压缩成六句话,随时回忆。