unisawp配对合约
方法名称 |
可视范围 |
类型 |
修饰符 |
Constructor |
Public ❗️ |
? |
NO❗️ |
initialize |
External ❗️ |
? |
NO❗️ |
getReserves |
Public ❗️ |
|
NO❗️ |
_safeTransfer |
Private ? |
? |
|
_update |
Private ? |
? |
|
_mintFee |
Private ? |
? |
|
mint |
External ❗️ |
? |
lock |
burn |
External ❗️ |
? |
lock |
swap |
External ❗️ |
? |
lock |
skim |
External ❗️ |
? |
lock |
sync |
External ❗️ |
? |
lock |
函数方法
constructor 构造函数
- 调用者赋值到工厂地址变量
initialize 初始化方法
* @param _token0 token0
* @param _token1 token1
* @dev 初始化方法,部署时由工厂调用一次
- 确认调用者为工厂合约地址
- 为token0,1赋值
getReserves 获取储备
* @return _reserve0 储备量0
* @return _reserve1 储备量1
* @return _blockTimestampLast 时间戳
* @dev 获取储备
- 返回储备量0,1和最后更新储备量的时间戳
_safeTransfer 私有安全发送
* @param token token地址
* @param to to地址
* @param value 数额
* @dev 私有安全发送
- 调用token合约地址的低级transfer方法
- 确认返回值为true并且返回的data长度为0或者解码后为true
_update 更新储量
* @param balance0 余额0
* @param balance1 余额1
* @param _reserve0 储备0
* @param _reserve1 储备1
* @dev 更新储量,并在每个区块的第一次调用时更新价格累加器
- 确认
余额0
和余额1
小于等于最大的uint112
- 区块时间戳,将时间戳转换为uint32
- 计算时间流逝
- 如果时间流逝>0 并且 储备量0,1不等于0
- 价格0最后累计 += 储备量1 * 2*112 / 储备量0 时间流逝
- 价格1最后累计 += 储备量0 * 2*112 / 储备量1 时间流逝
- 余额0,1放入储备量0,1
- 更新最后时间戳
- 触发同步事件
_mintFee 如果收费,铸造流动性相当于1/6的增长sqrt(k)
* @param _reserve0 储备0
* @param _reserve1 储备1
* @return feeOn
* @dev 如果收费,铸造流动性相当于1/6的增长sqrt(k)
- 查询工厂合约的feeTo变量值
- 如果feeTo不等于0地址,feeOn等于true否则为false
- 定义k值
- 如果feeOn等于true
- rootK = (储备量0*储备量1)的平方根
- rootKLast = k值的平方根
- 如果rootK>rootKLast
- 分子 = erc20总量 * (rootK - rootKLast)
- 分母 = rootK * 5 + rootKLast
- 流动性 = 分子 / 分母
- 如果流动性 > 0 将流动性铸造给feeTo地址
- 否则如果_kLast不等于0
mint 铸造方法
* @param to to地址
* @return liquidity 流动性数量
* @dev 铸造方法
* @notice 应该从执行重要安全检查的合同中调用此低级功能
- 获取
储备量0
,储备量1
- 获取当前合约在token0,token1合约内的
余额0
,余额1
数量0
= 余额0 - 储备量0;数量1
= 余额1 - 储备量1
- 调用铸造费方法,返回铸造费开关
- 如果pair合约的
总量
等于 0
- 则
- 流动性 = (数量0 * 数量1)的平方根 - 最小流动性1000
- 在总量为0的初始状态,永久锁定最低流动性1000
- 否则
- 流动性 = (数量0 总量 / 储备量0) 和 (数量1 总量 / 储备量1) 的最小值
- 确认
流动性
大于0
- 铸造流动性给to地址
- 更新储备量
- 如果铸造费开关为true, k值 = 储备量0 * 储备量1
burn 销毁方法
* @param to to地址
* @return amount0
* @return amount1
* @dev 销毁方法
* @notice 应该从执行重要安全检查的合同中调用此低级功能
- 获取
储备量0
,储备量1
- 带入变量
余额0,1
= 当前合约在token0,1
合约内的余额
- 流动性 = 当前合约的balanceOf映射中获取当前合约自身的流动性数量
- 返回税费开关
- 获取
总量
,必须在此处定义,因为总量
可以在mintFee中更新
- 数额0,1 = 流动性数量 * 余额0,1 / 总量, 使用余额确保按比例分配
- 确认数额0,1大于0
- 销毁当前合约内的流动性数量
- 将数额0,1数量的token0,1发送给to地址
余额0,1
= 当前合约在token0,1
合约内的余额
- 更新储备量(余额0,1,储备量0,1)
- 如果铸造费开关为true, k值 = 储备0 * 储备1
swap 交换方法
* @param amount0Out 输出数额0
* @param amount1Out 输出数额1
* @param to to地址
* @param data 用于回调的数据
* @dev 交换方法
* @notice 应该从执行重要安全检查的合同中调用此低级功能
- 确认
输出数量0,1
都大于0
- 获取
储备量0
,储备量1
- 确认
输出数量0,1
< 储备量0,1
- 初始化余额变量
- 初始化
token0,1
变量
- 确认to地址不等于
token0,1
- 如果
输出数量0,1
> 0 安全发送输出数量0,1
的token0,1
到to地址
- 如果data的长度大于0 调用to地址的接口
余额0,1
= 当前合约在token0,1
合约内的余额
- 如果 余额0 > 储备0 - 输出数量0
- 则 输入数量0 = 余额0 - (储备0 - 输出数量0)
- 否则 输入数量0 = 0
- 如果 余额1 > 储备1 - 输出数量1
- 则 输入数量1 = 余额1 - (储备1 - 输出数量1)
- 否则 输入数量1 = 0
- 确认
输入数量0||1
大于0
- 调整后的余额0 = 余额0 1000 - (输入数量0 3)
- 调整后的余额1 = 余额1 1000 - (输入数量1 3)
- 确认
调整后的余额0
调整后的余额1
>= 储备0 储备1 * 1000000
- 更新储备量(余额0,1,储备量0,1)
- 触发交换事件
skim 强制平衡以匹配储备
* @param to to地址
* @dev 强制平衡以匹配储备
- 初始化
token0,1
变量
- 将当前合约在
token0,1
的余额-储备量0,1
安全发送到to地址
sync 强制准备金与余额匹配
* @dev 强制准备金与余额匹配
- 更新储备量(当前合约在
token0,1
的余额0,1
,储备量0,1
)
unisawp工厂合约
创建配对
createPair 创建配对方法
* @param tokenA TokenA
* @param tokenB TokenB
* @return pair 配对地址
* @dev 创建配对
- 确认tokenA不等于tokenB
- 将tokenA和tokenB进行大小排序,确保token0小于token1
- 确认token0不等于0地址
- 确认配对映射中不存在token0=>token1
- 字节码 = "UniswapV2Pair"合约的创建字节码
- 盐值 = 将token0和token1打包后创建哈希
- 通过create2方法布署合约,并且加盐,返回地址到pair变量
- 调用pair地址的合约中的"initialize"方法,传入变量token0,token1
- 配对映射中设置token0=>token1=pair
- 配对映射中设置token1=>token0=pair
- 配对数组中推入pair地址
- 触发配对成功事件
设置收税
setFeeTo 设置收税地址
* @dev 设置收税地址
* @param _feeTo 收税地址
- 设置收税地址
setFeeToSetter 收税权限控制
* @dev 收税权限控制
* @param _feeToSetter 收税权限控制
- 设置收税权限控制
unisawp路由合约
方法名称 |
可视范围 |
类型 |
修饰符 |
Constructor |
Public |
? |
|
Fallback |
External |
? |
|
receive |
External |
? |
|
_addLiquidity |
Internal ? |
? |
|
addLiquidity |
External |
? |
ensure |
addLiquidityETH |
External |
? |
ensure |
removeLiquidity |
Public |
? |
ensure |
removeLiquidityETH |
Public |
? |
ensure |
removeLiquidityWithPermit |
External |
? |
|
removeLiquidityETHWithPermit |
External |
? |
|
removeLiquidityETHSupportingFeeOnTransferTokens |
Public |
? |
ensure |
removeLiquidityETHWithPermitSupportingFeeOnTransferTokens |
External |
? |
|
_swap |
Internal ? |
? |
|
swapExactTokensForTokens |
External |
? |
ensure |
swapTokensForExactTokens |
External |
? |
ensure |
swapExactETHForTokens |
External |
? |
ensure |
swapTokensForExactETH |
External |
? |
ensure |
swapExactTokensForETH |
External |
? |
ensure |
swapETHForExactTokens |
External |
? |
ensure |
_swapSupportingFeeOnTransferTokens |
Internal ? |
? |
|
swapExactTokensForTokensSupportingFeeOnTransferTokens |
External |
? |
ensure |
swapExactETHForTokensSupportingFeeOnTransferTokens |
External |
? |
ensure |
swapExactTokensForETHSupportingFeeOnTransferTokens |
External |
? |
ensure |
添加流动性方法
- pair合约拥有一套erc20代币的所有方法
- 用户准备TokenA和TokenB两个代币,期望数量AB,最小数量AB四个数值创建流动性
- 添加流动性方法根据期望AB数量和最小AB数量乘以储备量比例计算最优取出数量AB
- 流动性方法根据取出数量AB将Token存入pair合约
- pair合约为用户创建一个liquidity流动性数值,为存入数量AB的平方根
- 添加流动性方法分为两种,添加两个token的流动性和添加token和ETH的流动性
- 添加token和ETH的流动性方法会将ETH兑换成WETH再进行操作,
_addLiquidity 添加流动性私有方法
* @dev 添加流动性的私有方法
* @param tokenA tokenA地址
* @param tokenB tokenB地址
* @param amountADesired 期望数量A
* @param amountBDesired 期望数量B
* @param amountAMin 最小数量A
* @param amountBMin 最小数量B
* @return amountA 数量A
* @return amountB 数量B
- 如果TokenA,TokenB的配对合约不存在则创建pair
- 从
pair合约
获取 储备量A, 储备量B,储备量AB经过排序
- 如果储备reserveA, reserveB==0,
- 则返回值(数量A,数量B)=期望值(期望数量A,期望数量B)
- 否则
- 最优数量B = 期望数量A * 储备量B / 储备量A
- 如果最优数量B <= 期望数量B
- 则
- 确认最优数量B >= 最小数量B
- (数量A,数量B) = 期望数量A, 最优数量B
- 否则
- 最优数量A = 期望数量A * 储备量A / 储备量B
- 断言最优数量A <= 期望数量A
- 确认最优数量A >= 最小数量A
- (数量A,数量B) = 最优数量A, 期望数量B
addLiquidity 添加流动性方法
* @param token token地址
* @param amountTokenDesired 期望数量
* @param amountTokenMin Token最小数量
* @param amountETHMin ETH最小数量
* @param to to地址
* @param deadline 最后期限
* @return amountToken Token数量
* @return amountETH ETH数量
* @return liquidity 流动性数量
- (数量A,数量B) = _addLiquidity(tokenA地址,tokenB地址,期望数量A,期望数量B,最小数量A,最小数量B)
- 根据TokenA,TokenB地址,获取
pair合约
地址
- 将数量为
数量A
的tokenA从msg.sender账户中安全发送到pair合约
地址
- 将数量为
数量B
的tokenB从msg.sender账户中安全发送到pair合约
地址
- 流动性数量 = pair合约的铸造方法铸造给
to地址
的返回值
addLiquidityETH 添加ETH流动性方法
* @dev 添加ETH流动性方法
* @param token token地址
* @param amountTokenDesired Token期望数量
* @param amountTokenMin Token最小数量
* @param amountETHMin ETH最小数量
* @param to to地址
* @param deadline 最后期限
* @return amountToken Token数量
* @return amountETH ETH数量
* @return liquidity 流动性数量
- (Token数量,ETH数量) = _addLiquidity(token地址,WETH地址,Token期望数量,收到的主币数量,Token最小数量,ETH最小数量)
- 根据Token,WETH地址,获取
pair合约
地址
- 将
Token数量
的token从msg.sender账户中安全发送到pair合约
地址
- 向
WETH合约
存款ETH数量
的主币
- 将
ETH数量
的WETH
token发送到pair合约
地址
- 流动性数量 = pair合约的铸造方法铸造给
to地址
的返回值
- 如果
收到的主币数量
>ETH数量
则返还收到的主币数量
-ETH数量
移除流动性方法
- 将发送账户的流动性数量返还给pair合约
- 在pair合约中销毁流动性数量,然后根据最小数量AB计算返还给用户的tokenAB
- 移除流动性方法分两种,移除两个token的流动性,和移除token和ETH的流动性
- 这两种方法又分别拥有两个前置方法,带签名移除两个token流动性和带签名移除token和ETH流动性
- 除此之外还有支持收税的移除ETH流动性方法,和带签名支持收税的移除ETH流动性方法
removeLiquidity 移除流动性方法
* @dev 移除流动性
* @param tokenA tokenA地址
* @param tokenB tokenB地址
* @param liquidity 流动性数量
* @param amountAMin 最小数量A
* @param amountBMin 最小数量B
* @param to to地址
* @param deadline 最后期限
* @return amountA 数量A
* @return amountB 数量B
- 计算TokenA,TokenB的CREATE2地址,而无需进行任何外部调用
- 将流动性数量从用户发送到pair地址(需提前批准)
- pair合约销毁流动性数量,并将数值0,1的token发送到to地址
- 排序tokenA,tokenB
- 按排序后的token顺序返回数值AB
- 确保数值AB大于最小值AB
removeLiquidityETH 移除ETH流动性方法
* @dev 移除ETH流动性
* @param token token地址
* @param liquidity 流动性数量
* @param amountTokenMin token最小数量
* @param amountETHMin ETH最小数量
* @param to to地址
* @param deadline 最后期限
* @return amountToken token数量
* @return amountETH ETH数量
- (token数量,ETH数量) = 移除流动性(token地址,WETH地址,流动性数量,token最小数量,ETH最小数量,当前合约地址,最后期限)
- 将token数量的token发送到to地址
- 从WETH取款ETH数量
- 将ETH数量的ETH发送到to地址
removeLiquidityWithPermit 带签名移除流动性方法
* @dev 带签名移除流动性
* @param tokenA tokenA地址
* @param tokenB tokenB地址
* @param liquidity 流动性数量
* @param amountAMin 最小数量A
* @param amountBMin 最小数量B
* @param to to地址
* @param deadline 最后期限
* @param approveMax 全部批准
* @param v v
* @param r r
* @param s s
* @return amountA 数量A
* @return amountB 数量B
- 计算TokenA,TokenB的CREATE2地址,而无需进行任何外部调用
- 如果全部批准,value值等于最大uint256,否则等于流动性
- 调用pair合约的许可方法(调用账户,当前合约地址,数值,最后期限,v,r,s)
- (数量A,数量B) = 移除流动性(tokenA地址,tokenB地址,流动性数量,最小数量A,最小数量B,to地址,最后期限)
removeLiquidityETHWithPermit 带签名移除ETH流动性方法
* @dev 带签名移除ETH流动性
* @param token token地址
* @param liquidity 流动性数量
* @param amountTokenMin token最小数量
* @param amountETHMin ETH最小数量
* @param to to地址
* @param deadline 最后期限
* @param approveMax 全部批准
* @param v v
* @param r r
* @param s s
* @return amountToken token数量
* @return amountETH ETH数量
- 计算TokenA,TokenB的CREATE2地址,而无需进行任何外部调用
- 如果全部批准,value值等于最大uint256,否则等于流动性
- 调用pair合约的许可方法(调用账户,当前合约地址,数值,最后期限,v,r,s)
- (token数量,ETH数量) = 移除ETH流动性(token地址,流动性数量,token最小数量,ETH最小数量,to地址,最后期限)
交换方法
- 基础的交换方法有6种
- 根据精确的token交换尽量多的token
- 使用尽量少的token交换精确的token
- 根据精确的ETH交换尽量多的token
- 使用尽量少的token交换精确的ETH
- 根据精确的token交换尽量多的ETH
- 使用尽量少的ETH交换精确的token
- 交换方法调用时,可以传入两个token的交易对,或者传入多个token的路径地址数组
- 多个token的路径地址数组中,每前后两个token地址必须是一个已经配对的交易对
- 交换方法会遍历路径数组,将每两个交易对排序后调用交易对的pair合约的交换方法进行交易
- 除此之外交换方法还有3种支持收税的交换方法
- 支持收税的根据精确的token交换尽量多的token
- 支持收税的根据精确的ETH交换尽量多的token
- 支持收税的根据精确的token交换尽量多的ETH
_swap 私有交换方法
* @dev 私有交换
* @param amounts 数额数组
* @param path 路径
* @param _to to地址
- 遍历
路径数组
- (输入地址,输出地址) = (当前地址,下一个地址)
- token0 = 排序(输入地址,输出地址)
- 输出数量 = 数额数组下一个数额
- (输出数额0,输出数额1) = 输入地址==token0 ? (0,输出数额) : (输出数额,0)
- to地址 = i<路径长度-2 ? (输出地址,路径下下个地址)的pair合约地址 : to地址
- 调用(输入地址,输出地址)的
pair合约
地址的交换
方法(输出数额0,输出数额1,to地址,0x00)
swapExactTokensForTokens 根据精确的token交换尽量多的token
* @dev 根据精确的token交换尽量多的token
* @param amountIn 精确输入数额
* @param amountOutMin 最小输出数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
* @return amounts[] 数额数组
- 数额数组 ≈ 遍历路径数组((精确输入数额 储备量Out) / (储备量In 1000 + 输入数额))
- 确认数额数组最后一个元素>=最小最小输出数额
- 将数量为数额数组[0]的路径[0]的token从调用者账户发送到路径0,1的pair合约
- 私有交换(数额数组,路径数组,to地址)
swapTokensForExactTokens 使用尽量少的token交换精确的token
* @dev 使用尽量少的token交换精确的token
* @param amountOut 精确输出数额
* @param amountInMax 最大输入数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
* @return amounts[] 数额数组
- 数额数组 ≈ 遍历路径数组((储备量In 储备量Out 1000) / (储备量Out - 输出数额 * 997) + 1)
- 确认数额数组第一个元素<=最大输入数额
- 将数量为数额数组[0]的路径[0]的token从调用者账户发送到路径0,1的pair合约
- 私有交换(数额数组,路径数组,to地址)
swapExactETHForTokens 根据精确的ETH交换尽量多的token
* @dev 根据精确的ETH交换尽量多的token
* @param amountOutMin 最小输出数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
* @return amounts[] 数额数组
- 确认路径第一个地址为WETH
- 数额数组 ≈ 遍历路径数组((精确输入数额 储备量Out) / (储备量In 1000 + msg.value))
- 确认数额数组最后一个元素>=最小输出数额
- 将数额数组[0]的数额存款ETH到WETH合约
- 断言将数额数组[0]的数额的WETH发送到路径(0,1)的pair合约地址
- 私有交换(数额数组,路径数组,to地址)
swapTokensForExactETH 使用尽量少的token交换精确的ETH
* @param amountOut 精确输出数额
* @param amountInMax 最大输入数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
* @return amounts[] 数额数组
- 确认路径最后一个地址为WETH
- 数额数组 ≈ 遍历路径数组((储备量In 储备量Out 1000) / (储备量Out - 输出数额 * 997) + 1)
- 确认数额数组第一个元素<=最大输入数额
- 将数量为数额数组[0]的路径[0]的token从调用者账户发送到路径0,1的pair合约
- 私有交换(数额数组,路径数组,to地址)
- 从WETH合约提款数额数组最后一个数值的ETH
- 将数额数组最后一个数值的ETH发送到to地址
swapExactTokensForETH 根据精确的token交换尽量多的ETH
* @dev 根据精确的token交换尽量多的ETH
* @param amountIn 精确输入数额
* @param amountOutMin 最小输出数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
* @return amounts[] 数额数组
- 确认路径最后一个地址为WETH
- 数额数组 ≈ 遍历路径数组((精确输入数额 储备量Out) / (储备量In 1000 + 输入数额))
- 确认数额数组最后一个元素>=最小输出数额
- 将数量为数额数组[0]的路径[0]的token从调用者账户发送到路径0,1的pair合约
- 私有交换(数额数组,路径数组,当前合约地址)
- 从WETH合约提款数额数组最后一个数值的ETH
- 将数额数组最后一个数值的ETH发送到to地址
swapETHForExactTokens 使用尽量少的ETH交换精确的token
* @dev 使用尽量少的ETH交换精确的token
* @param amountOut 精确输出数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
* @return amounts[] 数额数组
- 确认路径第一个地址为WETH
- 数额数组 ≈ 遍历路径数组((储备量In 储备量Out 1000) / (储备量Out - 输出数额 * 997) + 1)
- 确认数额数组第一个元素<=msg.value
- 将数额数组[0]的数额存款ETH到WETH合约
- 断言将数额数组[0]的数额的WETH发送到路径(0,1)的pair合约地址
- 私有交换(数额数组,路径数组,to地址)
- 如果
收到的主币数量
>数额数组[0]
则返还收到的主币数量
-数额数组[0]
_swapSupportingFeeOnTransferTokens 支持收税的私有交换
* @dev 支持收税的私有交换
* @notice 要求初始金额已经发送到第一对
* @param path 路径数组
* @param _to to地址
- 遍历
路径数组
- (输入地址,输出地址) = (当前地址,下一个地址)
- token0 = 排序(输入地址,输出地址)
- pair地址 = (输入地址,输出地址)
- 初始化输入数值,输出数值
- 获取储备_reserve0,_reserve1
- 排序(储备量In,储备量Out)
- 输入数额 = pair地址在token合约的余额 - 储备量In
- 输出数额 = (输入数额 储备量Out) / (储备量In 1000 + 输入数额)
- (输出数额0,输出数额1) = 输入地址 == token0 ? (0,输出数额0) : (输出数额0,0)
- to地址 = 当前循环到倒数第二 ? pair地址(输出地址,路径最后一个地址) : _to地址
- 交换(输出数额0,输出数额1,to地址,0x00)
swapExactTokensForTokensSupportingFeeOnTransferTokens 支持收税的根据精确的token交换尽量多的token
* @dev 支持收税的根据精确的token交换尽量多的token
* @param amountIn 精确输入数额
* @param amountOutMin 最小输出数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
- 将数量为数额数组[0]的路径[0]的token从调用者账户发送到路径0,1的pair合约
- 记录to地址在路径数组最后一个token地址的余额
- 支持收税的私有交换(路径数组,to地址)
- 确认to地址在路径数组最后一个token地址的当前余额 - 之前的余额 >= 最小输出数额
swapExactETHForTokensSupportingFeeOnTransferTokens 支持收税的根据精确的ETH交换尽量多的token
* @dev 支持收税的根据精确的ETH交换尽量多的token
* @param amountOutMin 最小输出数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
- 确认路径第一个地址为WETH
- 输入数额为msg.value
- 将输入数额存款ETH到WETH合约
- 断言将输入数额的WETH发送到路径(0,1)的pair合约地址
- 记录to地址在路径数组最后一个token地址的余额
- 支持收税的私有交换(路径数组,to地址)
- 确认to地址在路径数组最后一个token地址的当前余额 - 之前的余额 >= 最小输出数额
swapExactTokensForETHSupportingFeeOnTransferTokens 支持收税的根据精确的token交换尽量多的ETH
* @dev 支持收税的根据精确的token交换尽量多的ETH
* @param amountIn 精确输入数额
* @param amountOutMin 最小输出数额
* @param path 路径数组
* @param to to地址
* @param deadline 最后期限
- 确认路径最后一个地址为WETH
- 将数量为数额数组[0]的路径[0]的token从调用者账户发送到路径0,1的pair合约
- 支持收税的私有交换(路径数组,当前合约地址)
- 输出数额 = 当前合约地址在WETH的余额
- 确认输出数额 >= 最小输出数额
- 从WETH合约提款输出数额
- 将输出数额的ETH发送到to地址