欢迎订阅专栏:3分钟Solidity--智能合约--Web3区块链技术必学
Uniswap V2 最优单边供应
要获取该内容的最新版本,请访问 Cyfrin.io 上的 Uniswap V2 最优单边供应(代码示例)。
Uniswap V2 最优单边供应是一种便利功能,它通过链上计算和内部兑换,让用户仅用一种资产即可提供流动性,并确保在操作完成时,用户的全部投入资本都按最优比例转化为了流动性头寸,而无需用户手动进行资产拆分和兑换。 这对于希望简化操作流程的持币者来说非常有用。
最优单边供应
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract TestUniswapOptimalOneSidedSupply {
address private constant FACTORY =
0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address private constant ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address private constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
function sqrt(uint256 y) private pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
/*
s = 最佳交换金额
r = 代币a的储备金额
a = 用户当前拥有的代币a的数量(尚未添加到储备中)
f = 交换费百分比
s = (sqrt(((2 - f)r)^2 + 4(1 - f)ar) - (2 - f)r) / (2(1 - f))
*/
function getSwapAmount(uint256 r, uint256 a)
public
pure
returns (uint256)
{
return (sqrt(r * (r * 3988009 + a * 3988000)) - r * 1997) / 1994;
}
/* 最优单边供应
1. 从代币A最优兑换到代币B
2. 添加流动性
*/
function zap(address _tokenA, address _tokenB, uint256 _amountA) external {
require(_tokenA == WETH || _tokenB == WETH, "!weth");
IERC20(_tokenA).transferFrom(msg.sender, address(this), _amountA);
address pair = IUniswapV2Factory(FACTORY).getPair(_tokenA, _tokenB);
(uint256 reserve0, uint256 reserve1,) =
IUniswapV2Pair(pair).getReserves();
uint256 swapAmount;
if (IUniswapV2Pair(pair).token0() == _tokenA) {
// 从token0交换到token1
swapAmount = getSwapAmount(reserve0, _amountA);
} else {
// 从token1兑换为token0
swapAmount = getSwapAmount(reserve1, _amountA);
}
_swap(_tokenA, _tokenB, swapAmount);
_addLiquidity(_tokenA, _tokenB);
}
function _swap(address _from, address _to, uint256 _amount) internal {
IERC20(_from).approve(ROUTER, _amount);
address[] memory path = new address[](2);
path = new address[](2);
path[0] = _from;
path[1] = _to;
IUniswapV2Router(ROUTER).swapExactTokensForTokens(
_amount, 1, path, address(this), block.timestamp
);
}
function _addLiquidity(address _tokenA, address _tokenB) internal {
uint256 balA = IERC20(_tokenA).balanceOf(address(this));
uint256 balB = IERC20(_tokenB).balanceOf(address(this));
IERC20(_tokenA).approve(ROUTER, balA);
IERC20(_tokenB).approve(ROUTER, balB);
IUniswapV2Router(ROUTER).addLiquidity(
_tokenA, _tokenB, balA, balB, 0, 0, address(this), block.timestamp
);
}
}
interface IUniswapV2Router {
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}
interface IUniswapV2Factory {
function getPair(address token0, address token1)
external
view
returns (address);
}
interface IUniswapV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount)
external
returns (bool);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount)
external
returns (bool);
}