UniswapV2源码分析
文章目录
UniSwap-v2 源码阅读
源码分布
规则
使用A*B这个固定数值进行计算
入口
入口在v2-periphery处,可以先看看简单的一些方法
addLiquidity
- 添加流动性方法
|
|
流程说明
- 调用私有方法_addLiquidity计算要添加的tokenA和tokenB的amount
- 通过
factory合约
获取pair是否存在,不存在则通过createPair创建一个lp- 对交易对排序
- 通过UniswapV2Pair.createionCode来创建合约
- 计算合约的地址
- 调用创建的合约的initialize方法
factory合约
保存交易对到getPairfactory合约
保存创建的合约地址到allPairs
- 获取pair的余额(reserveA, reserveB)
- 通过quote计算需要的数量
- needB = giveA*reserveB/reserveA,
- 如果needB小于giveB,则使用needB替代giveB
- 如果needB大于giveB, 则计算 needA = giveB*reserveA/reserveB
- 如果needA小于giveA,则使用needA替换giveA,否则失败
- 通过
- 获取tokenA/tokenB的LP的合约地址
- 这里是通过abi直接计算的,而不是通过调用方法,可以借鉴一下
- 将计算出来的tokenA的amount转到LP合约里
- 将计算出来的tokenB的amount转到LP合约里
- 调用LP合约的mint方法
- 获取LP当前的pool(reserve0,reserve1)
- 获取LP的token0和token1 的余额
- 用token的余额-pool的余额,计算amount0 和 amount1
- PS:这里没有判断是不是由这个地址转进合约的,所以是不是存在一个可能,让其他人转币进去,然后我们自己调用mint,to填写自己的地址,这样就相当于我们的lp。但是必须在同一个交易里实现这个操作。
- PS:通过钓鱼或者flashloan去完成?可以看一下flashloan的代码,比如还款的时候调用一下
- 计算手续费 _mintFee
- 获取手续费地址
- 获取Klast(klast=reserve0*reserver1)
- todo
- 获取totalSupply
- 如果是0
- lp = sqrt(amount0*amount1).sub(10**3)
- _mint(address(0), 10**3)
- 记录balance和totalSupply
- 如果不是0
- lp = min(amount0totalSupply/reserve0, amount1totalSupply/reserve1)
- 如果是0
- _mint(to, lp), 将lp转到to地址下
- _update更新
- 记录 blockTimestamp
- 记录 reserve0
- 记录 reserve1
- 发送 sync事件 📧️
- 发送 mint事件 📧️
removeLiquidity
- 移除流动性
|
|
流程说明
- 获取lp的地址
- 将liquidity转回pair
- 调用pari的burn方法
- 获取reserve0, reserve1
- 获取balance0, balance1
- 获取当前地址的liquidity
- 计算手续费 _mintFee
- amount0 = liquidity*balance0/totalSupply
- amount1 = liquidity*balance1/totalSupply
- _burn liquidity
- totalSupply 减少, 然后address的balance减少
- 将token0 转到to
- 将token1 转到to
- 调用 _update方法更新reserve0 和 reserve1
- 发送 sync事件 📧️
- 发送 burn事件 📧️
swapExactTokensForTokens
- 用A换B
|
|
流程说明
- getAmountOut 计算可以换出多少币
- 获取 reserveIn, reserveOut
- 通过getAmount 计算兑换
- fee是 3/1000
- 不计算手续费的公式为 AB = (A+a)(B-x), 简化一下就是 x=(B*a)/(A+a)
- 通过getAmount 计算兑换
- 获取 reserveIn, reserveOut
- 将币转到lp地址
- 调用_swap方法
- 调用pair的swap方法
- 获取当前的reserve0 和 reserve1
- transfer token0
- transfer token1
- 如果存在calldata,则调用calldata
- PS:这里的calldata开启了flashloan的功能
- 重新更新 balance0Adjusted, balance1Adjusted
- _update
- 发送 sync事件 📧️
- 发送Swap事件 📧️
- 调用pair的swap方法
swapTokensForExactTokens
- 同上,用B换A
|
|
总结
Uniswap的代码还是史无前例的,特别是swap时的支持的call,是一种很hack的方法。
文章作者 chuwt
上次更新 2021-12-17