AMM储备:分开账面储备与代币余额
AMM记录储备与实际代币余额可能不同。直接转入可改变balanceOf,却不立即改变getReserves,也不自动发行LP代币。解释差额时,应重建pair状态过渡,不能把每次余额增加都叫新增流动性资本或费用收入。
本题研究所引Uniswap v2实现,不假定所有AMM、克隆合约与特殊代币行为相同,也不建议提取余额盈余。
工作表保留三个对象
第一项是pair记录的token0、token1储备,第二项是两个代币合约对pair的实际balanceOf,第三项是LP所有权账,包括总量与被研究持有人数量。
在对齐状态边界读取三者。昨天储备与今天余额比较,可能造出从未同时存在的盈余;交易级归因还需排除整块快照里的其他转账和pair动作。
v2 Pair源码中的getReserves、_update、skim及sync给出这里的机制:_update将余额记为储备,skim转走余额超出储备部分,sync将储备更新为当前余额。这两个函数自身都没有LP份额铸造。
保存查阅版本,若评价真实部署,还要匹配实际代码。参考仓库存在,不证明任意同名池使用这些字节。代码身份未核时,条件性说明比直接归类更准确。
假设主例:直接转入十单位
假设普通代币精确转移、无rebase、无其他变化。pair P起始储备各一百,实际余额也各一百;LP总量一万,H持一千,占百分之十。
外部地址直接向P转十token0,不调用mint。随后实际余额一百一十与一百,记录储备仍各一百,LP总量仍一万。发送者没有通过这次直接转移获得新LP份额。
| 字段 | 转入前 | 直接转入后 |
|---|---|---|
| 记录reserve0 | 一百 | 一百 |
| 记录reserve1 | 一百 | 一百 |
| 实际balance0 | 一百 | 一百一十 |
| 实际balance1 | 一百 | 一百 |
| balance0减reserve0 | 零 | 十 |
| LP总量 | 一万 | 一万 |
| H的份额比例 | 一千除一万为百分之十 | 百分之十 |
比例未变不独自确定全部权利的价值或可提取性,但说明假设直接转入本身没有向发送者发行LP仓位。要称作LP资本贡献,应找到实际流动性事件,不能只看token Transfer。
原始单位和代币顺序也需固定。如果一个工具以整枚显示、另一个以最小单位显示,所谓十单位盈余可能只是量纲错配。先核值再讨论机制。
将skim与sync作为替代路径
从相同转入后状态出发,路径A成功执行skim,按假设普通代币行为将超额十token0转给指定接收者。实际余额恢复各一百,储备仍各一百,这次调用不铸LP。
替代路径B执行sync,将reserve0记一百一十、reserve1仍一百;函数不把差额转走,也不在该调用铸LP。十单位在这条历史中留于pair。
| 共同起点后的结果 | 路径A:skim | 路径B:sync |
|---|---|---|
| 实际balance0 | 一百 | 一百一十 |
| 记录reserve0 | 一百 | 一百一十 |
| balance1与reserve1 | 一百 | 一百 |
| 给接收者盈余 | 十token0 | 零 |
| 本调用新增LP | 零 | 零 |
两路径是互斥演示。没有中间新转入,不能既减掉skim十,又保留同一十作sync增加。真实多调用必须按时间顺序还原,而非把各函数可能结果都加进账。
B路径记录乘积从一百乘一百等于一万,变成一百一十乘一百等于一万一千,假设却没有swap。因此,储备乘积升高不单独证明成交量或交易者支付费用。
用状态区分事件含义
代币Transfer记录代币特定移动,pair的Mint、Burn、Swap、Sync记录不同操作,名称不是可以互换的经济确认。
LP资本主张需连接份额发行及相应资产移动;费用主张需连接具体机制和接收方。不能因为pair资产增加就把直接转入叫费用,也不能从未知发送者推断其捐赠动机。
源码另有与流动性事件相连的协议费逻辑,后续fee mint可能依赖累计状态。“sync自身不铸LP”是窄观察,不能扩张成该数量绝不会影响任何未来费用记账。
毛代币移动、储备更新、份额发行、费用处理应四栏并列,其时间差正是本表要揭示的机制。若来源只给总TVL和LP数量,无法恢复差额发生在哪一笔,应保留归因未知。
不同边界:余额低于储备
另设负rebase代币,使P的token0余额从一百降至九十,记录reserve0仍一百。此时是缺口十,不是可分发的负盈余。
参考skim使用受检查减法,较小余额减较大储备可能回滚。失败不证明储备没有不一致,应实际读两种余额和调用结果,而不是只凭错误提示分类。
若随后合法sync记录九十,则是余额变化传到储备,不是卖出十的交易证据。rebase本身需要代币材料;pair工作表解释其如何到达储备层,两种研究对象不能互相替代。
特殊转移会破坏简单算术
税费代币可能令接收者少收,某些代币对零数量转移也有特殊要求。应读实际实现并对前后余额,不能假设成功返回就有普通一比一收款。
例如在特别规定接收侧税百分之十的模型中,名义十单位盈余转移可净到九。不能推广别的代币,也不能只凭缺一反推存在税;费用、rebase、漏交易和单位错都有可能。
克隆pair也可能有不同函数、权限或储备规则。此v2代码不是全部分析面板余额差的统一分类系统。若代码不匹配,应收窄为观察到的差额,不冒称已找到原因。
差额不直接给观察者所有权
即使机制解释完整,也不能从可见盈余直接推出它属于研究者、某个LP或发送者。需区分合约可执行路径、名义余额归属和链下安排,不能用一个公开数值产生额外权利主张。
持有人H的百分之十是LP份额比例,不是任意时点保证收到两种代币固定数量的承诺。若研究需要赎回,还应核相应操作及条件,不能把本题储备桥误当个人提款报价。
后续费用事件要单算
再给独立原始单位例:起始两储备各一百万,LP总量一百万,跟踪kLast为十的十二次方。直接转入后sync把储备记为一百一十万与一百万,但假设kLast仍为旧值;协议费开关打开,后来一笔流动性操作整体成功。
在其_mintFee步骤,当前储备乘积的整数平方根是一百零四万八千八百零八,旧kLast根为一百万,相差四万八千八百零八。按源码计算,一百万乘差额作为分子,分母是五乘当前根再加旧根,分别得48,808,000,000与6,244,040,整数相除向下得七千八百一十六协议LP单位。
这只演示该步骤,其余成功操作还有自己的资产和份额账。若外层操作最终回滚,中间铸造不能当完成。案例是假设状态过渡,不是线上实测;即使算出费用份额,也不证明储备增长来自交易者,因为前提明示直接转入。
实际核验还需确认feeTo开关、kLast是否真保持、总LP量与取整都来自同一状态。不能把人工选的旧根用于真实池,再宣称复算出了真实协议收入。单位例与前面一百储备例彼此独立,不混其LP数量。
对另一接收税模型,名义转十可以令pair少十、接收者加九、另一个单位按规定税处理。应核三项归属或扣除,而不是强求实收九等于发出十。税可能由销毁或其他接收安排处理,未取得证据就不能编去向。
若沿时间连续执行skim再sync,第一步已把本例十盈余移走,之后无新流量时sync记录仍各一百,不是再增加至一百一十。用同起点的替代路径作对照,有助于发现分析脚本把函数模板当实际顺序的错误。
Sync事件也不单独证明调用过显式sync函数。参考代码由_update发事件,其他pair操作同样可以使用它。应保留周围调用与其他事件,再命名储备变化来源;只查事件名,可能把一次swap或mint中的储备更新误称为单独同步。
可执行对账表
| 操作 | 保存材料 | 防止误读 |
|---|---|---|
| 固定pair | 网络、顺序、代码、截止点 | 参考行为套错误部署 |
| 读双账 | 同状态储备与balanceOf | 用一种代替另一种 |
| 查所有权 | LP总量与真实发行 | 每次转入都当LP资本 |
| 重建路径 | 直接转移及后续调用 | skim与sync替代结果双算 |
| 核接收者 | 实收数量与代币行为 | 名义量等于净收款 |
| 分类经济影响 | 资产、储备、份额、费用 | 乘积增长等于交易量 |
储备更新、特殊代币事件、交易边界更正或代码核实后,应重核。发布余额储备差、解释和未知部分,形成可复算状态桥,而不把可见盈余等同自然流动性增长。
常见问题
直接向pair转代币会自动铸LP吗?
所引机制不会。需要检查mint与实际份额账,不能仅凭Transfer推所有权。
sync会将差额转给接收者吗?
参考实现只是更新储备,盈余转移是另一skim函数在适用条件下的作用。