LP流动性质押挖矿系统开发(现成源代码)
Uniswap 代码结构
Uniswap 智能合约代码由两个 github 项目组成。一个是 core,一个是 periphery。
core 偏核心逻辑,单个 swap 的逻辑。periphery 偏外围服务,一个个 swap 的基础上构建服务。单个 swap,两种代币形成的交易对,俗称“池子”。每个交易对有一些基本属性:reserve0/reserve1 以及 total supply。reserve0/reserve1 是交易对的两种代币的储存量。total supply 是当前流动性代币的总量。每个交易对都对应一个流动性代币(LPT-liquidity provider token)。简单的说,LPT 记录了所有流动性提供者的贡献。所有流动性代币的总和就是 total supply。Uniswap 协议的思想是 reserve0*reserve1 的乘积不变。
Periphery 逻辑
核心逻辑实现在 UniswapV2Router02.sol 中。称为 Router,因为 Periphery 实现了“路由”,支持各个 swap 之间的连接。基本上实现了三个功能:1/add liquidity(增加流动性)2/remove liqudity(抽取流动性)3/swap(交换)。
1.add liqudity
增加流动性,就是同时提供两种代币。因为代币有可能是 ETH,针对不同情况有不同的接口。逻辑类似。
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
)external virtual override ensure(deadline)returns(uint amountA,uint amountB,uint liquidity)
add liqudity 查看之前有没有创建相应的交易对。如果有相应的交易对,确定目前的兑换比例在希望的范围内(期望 amountDesired 和不低于 amountMin)。如果兑换比例 OK,将相应的代币转入对应的交易对池子,并调用其的 mint 函数。
2.remove liqudity
提供流动性的相反的操作就是抽取流动性。也就是说,流动性提供者不再提供相应的流动性:
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
)public virtual override ensure(deadline)returns(uint amountA,uint amountB){
liquidity 是抽取的流动性的量。amountMin 是抽取代币的最小的个数。to 是抽取代币的目标地址。deadline 是个有意思的设计:抽取的操作有时效性。超过了一定的 deadline(区块高度),这次抽取操作看成无效。
先收回需要抽取的 Token,并且销毁:
IUniswapV2Pair(pair).transferFrom(msg.sender,pair,liquidity);//send liquidity to pair
(uint amount0,uint amount1)=IUniswapV2Pair(pair).burn(to);
3.swap
swap 是普通用户进行代币交易的操作。普通用户通过 swap 操作实现两种 token 之间的交易。
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[]calldata path,
address to,
uint deadline
)external virtual override ensure(deadline)returns(uint[]memory amounts){
Uniswap 支持多种代币的交换。具体的含义是,Uniswap 提供了多级交易池的路由功能。举个例子,已有两个交易对 TokenA-TokenB,以及 TokenB-TokenC,通过 swap 接口,可以实现 TokenA-TokenC 的交换,其中经过的 TokenA-TokenB,TokenB-TokenC,称为路径(path)。amountIn 是路径中的第一个代币的数量,amountOutMin 是期望的交换后的最少的数量。
amounts=UniswapV2Library.getAmountsOut(factory,amountIn,path);
require(amounts[amounts.length-1]>=amountOutMin,UniswapV2Router:INSUFFICIENT_OUTPUT_AMOUNT);
amounts 是每个路径上的交换后的数量。amounts[amounts.length-1]也就是最后一条路径的输出数量。注意,UniswapV2Library.getAmountsOut 的实现(在获取每个交易对的 reserve 信息后,调用 getAmountOut 函数):
发表回复