当前位置: 首页 > 后端技术 > Java

LP流动性挖矿系统开发理念,详细逻辑

时间:2023-04-02 10:06:33 Java

Uniswap代码结构  Uniswap智能合约代码由两个github项目组成。一个是核心,一个是外围。  https://github.com/Uniswap/un...  https://github.com/Uniswap/un...  core部分核心逻辑,(LP流动性挖矿系统开发,详解对接v+hkkf5566)单次swap的逻辑。Periphery是一种外围服务,服务建立在一个一个交换的基础上。单次掉期,由两种代币组成的交易对,俗称“池子”。每个交易对都有一些基本属性:reserve0/reserve1和总供应量。reserve0/reserve1是交易对的两个代币的存储量。总供应量是当前流动性代币的总量。每个交易对对应一个流动性代币(LPT-liquidityprovidertoken)。简单来说,LPT记录了所有流动性提供者的贡献。所有流动性代币的总和就是总供应量。Uniswap协议的思想是reserve0*reserve1的乘积不变。  外围逻辑  核心逻辑在UniswapV2Router02.sol中实现。之所以称为Router,是因为Periphery实现了“路由”,支持swap之间的连接。基本上实现了三个功能:1/addliquidity(增加流动性)2/removeliquidity(抽取流动性)3/swap(兑换)。  1.增加流动性  增加流动性就是同时提供两种代币。因为token可能是ETH,所以不同的情况会有不同的接口。逻辑是相似的。  函数addLiquidity(  地址代币A,  地址代币B,  单位数量ADesired,  单位数量BDesired,  单位数量AMin,  单位数量BMin,  地址到,  uint截止日期  )externalvirtualoverrideensure(deadline)returns(uintamountA,uintamountB,uintliquidity)  addliquidity检查之前是否创建过对应的交易对。如果存在对应的交易对,请确保当前兑换比例在期望范围内(期望amountDesired且不小于amountMin)。如果兑换比例OK,将对应的代币转入对应的交易对池,并调用其铸币函数。  2。removeliquidity  提供流动性的相反操作是抽取流动性。也就是说,流动性提供者不再提供相应的流动性:  functionremoveLiquidity(  addresstokenA,  addresstokenB,  uintliquidity,  uintamountAMin,  uintamountBMin,  addressto,  uintdeadline  )publicvirtualoverrideensure(deadline)returns(uintamountA,uintamountB){  liquidity是提取流动性的数量。amountMin是要提取的最小代币数量。to是提取代币的目的地址。deadline是一个有趣的设计:提取操作是时间敏感的。如果超过某个期限(区块高度),提取操作将被视为无效。  先取出需要取出的Token,并销毁:  IUniswapV2Pair(pair).transferFrom(msg.sender,pair,liquidity);//发送流动性给pair  (uintamount0,uintamount1)=IUniswapV2Pair(pair).burn(to);  3.swap  swap是普通用户进行代币交易的操作。普通用户通过互换操作实现两种代币之间的交易。  函数swapExactTokensForTokens(  uintamountIn,  uintamountOutMin,  address[]calldatapath,  addressto,  uintdeadline  )externalvirtualoverrideensure(deadline)returns(uint[]memoryamounts){  Uniswap支持多代币兑换。具体意思是Uniswap为多级交易池提供路由功能。例如,有两个交易对TokenA-TokenB和TokenB-TokenC。通过交换接口,可以实现TokenA-TokenC的交换。传递的TokenA-TokenB和TokenB-TokenC称为路径。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的实现(获取各交易对的储备信息后,调用getAmountOut函数):  functiongetAmountOut(uintamountIn,uintreserveIn,uintreserveOut)internalpurereturns(uintamountOut){  require(amountIn>0,'UniswapV2Library:INSUFFICIENT_INPUT_AMOUNT');  require(reserveIn>0&&reserveOut>0,'UniswapV2Library:INSUFFICIENT_LIQUIDITY');  uintamountInWithFee=amountIn.mul(997);  uintnumerator=amountInWithFee.mul(reserveOut);  uintdenominator=reserveIn.mul(1000).add(amountInWithFee);  amountOut=分子/分母;  }  注意系数997/1000。在进入每个交易池之前,进入的金额先扣除本金的0.3%。这是交易费。需要注意的是,路径上的交易池是由每个池收集的。有点像高速收费站,一段一段收费。  TransferHelper.safeTransferFrom(  path[0],msg.sender,UniswapV2Library.pairFor(factory,path[0],path[1]),amounts[0]  );  将替换Coinpath[0],转入交易对,金额为amounts[0]。token转出后,进行真正的swap操作:1;i++){  (地址输入,地址输出)=(路径,路径[i+1]);  (地址token0,)=UniswapV2Library.sortTokens(输入,输出);  uintamountOut=amounts[i+1];  (uintamount0Out,uintamount1Out)=input==token0?(uint(0),amountOut):(amountOut,uint(0));  addressto=i0)_safeTransfer(_token0,to,amount0Out);//优化转移代币  if(amount1Out>0)_safeTransfer(_token1,to,amount1Out);//优化转移代币  因为兑换金额已经在swapExactTokensForTokens的getAmountOut函数中确定。所以,先直接转账。  在进行掉期之前,余额应等于准备金。通过balance和reserve的差值,可以反转token投入的数量:  uintamount0In=balance0>_reserve0-amount0Out?balance0-(_reserve0-amount0Out):0;  uintamount1In=balance1>_reserve1-amount1Out?balance1-(_reserve1-amount1Out):0;  确保反向推送的输入代币数量不小于零。  require(amount0In>0||amount1In>0,'UniswapV2:INSUFFICIENT_INPUT_AMOUNT');

最新推荐
猜你喜欢