Solidity Uniswap V2 Pair中移除流动性

        移除流动性与提供流动性是截然相反的一个动作。从Pool中移除流动性意味着烧销毁LP-Token,以换取pair中相应数量的Token。返回的token数量与提供的流动性是这样计算的:

        简而言之,返回的Token数量,与持有的LP-Token数量与LP-Token总供应量成正比。你的LP-Token份额越大,你在burn后从reserve获得的份额就越大。

        这就是我们实现burn函数所需要知道的:

        当有人向池提供流动性时,他们会得到 LP-token作为回报。当流动性被移除时,这些 LP-token会被兑换成池流动性并被销毁。让用户向合约发送一定数量的 LP-token,在合约中计算出用户可以获取的token后,销毁 LP-token。

function burn(address to) public returns (uint256 amount0, uint256 amount1)  {

  uint256 balance0 = IERC20(token0).balanceOf(address(this));

  uint256 balance1 = IERC20(token1).balanceOf(address(this));

  uint256 liquidity = balanceOf[address(this)];



  uint256 amount0 = (liquidity * balance0) / totalSupply;

  uint256 amount1 = (liquidity * balance1) / totalSupply;



  if (amount0 <= 0 || amount1 <= 0) revert InsufficientLiquidityBurned();



  _burn(address(this), liquidity);



  bool success0 = IERC20(token0).transfer(to, amount0);

        if (!success0)

            revert TransferFailed();

  bool success1 = IERC20(token1).transfer(to, amount1);

        if (!success1)

            revert TransferFailed();



  balance0 = IERC20(token0).balanceOf(address(this));

  balance1 = IERC20(token1).balanceOf(address(this));



  (uint112 reserve0_, uint112 reserve1_, ) = getReserves();

  _update(balance0, balance1, reserve0_, reserve1_);



  emit Burn(msg.sender, amount0, amount1);

}

接下来测试一下:

function testBurn() public {

        token0.transfer(address(pair), 1 ether);

        token1.transfer(address(pair), 1 ether);



        pair.mint(address(this));



        uint256 liquidity = pair.balanceOf(address(this));

        pair.transfer(address(pair), liquidity);

        pair.burn(address(this));



        assertEq(pair.balanceOf(address(this)), 0);

        assertReserves(1000, 1000);

        assertEq(pair.totalSupply(), 1000);

        assertEq(token0.balanceOf(address(this)), 10 ether - 1000);

        assertEq(token1.balanceOf(address(this)), 10 ether - 1000);

    }

我们可以看到,除了发送到零地址的最低流动性外,Pool又回到了未初始化的状态。

现在,让我们看看在提供不平衡的流动性后会发生什么:

function testBurnUnbalanced() public {

        token0.transfer(address(pair), 1 ether);

        token1.transfer(address(pair), 1 ether);



        pair.mint(address(this));



        token0.transfer(address(pair), 2 ether);

        token1.transfer(address(pair), 1 ether);



        pair.mint(address(this)); // + 1 LP



        uint256 liquidity = pair.balanceOf(address(this));

        pair.transfer(address(pair), liquidity);

        pair.burn(address(this));



        assertEq(pair.balanceOf(address(this)), 0);

        assertReserves(1500, 1000);

        assertEq(pair.totalSupply(), 1000);

        assertEq(token0.balanceOf(address(this)), 10 ether - 1500);

        assertEq(token1.balanceOf(address(this)), 10 ether - 1000);

    }

        我们在这里看到的是,我们损失了 500 wei的Token 0!这就是上文提到的对价格操纵的惩罚。但这个数额小得离谱,看起来一点都不重要。这是因为我们当前的用户是唯一的流动性提供者。如果我们向另一个用户初始化的池提供了不平衡的流动性,会怎么样呢?让我们来看看:

function testBurnUnbalancedDifferentUsers() public {

        testUser.provideLiquidity(

            address(pair),

            address(token0),

            address(token1),

            1 ether,

            1 ether

        );



        assertEq(pair.balanceOf(address(this)), 0);

        assertEq(pair.balanceOf(address(testUser)), 1 ether - 1000);

        assertEq(pair.totalSupply(), 1 ether);



        token0.transfer(address(pair), 2 ether);

        token1.transfer(address(pair), 1 ether);



        pair.mint(address(this)); // + 1 LP



        uint256 liquidity = pair.balanceOf(address(this));

        pair.transfer(address(pair), liquidity);

        pair.burn(address(this));



        // this user is penalized for providing unbalanced liquidity

        assertEq(pair.balanceOf(address(this)), 0);

        assertReserves(1.5 ether, 1 ether);

        assertEq(pair.totalSupply(), 1 ether);

        assertEq(token0.balanceOf(address(this)), 10 ether - 0.5 ether);

        assertEq(token1.balanceOf(address(this)), 10 ether);



        testUser.removeLiquidity(address(pair));



        // testUser receives the amount collected from this user

        assertEq(pair.balanceOf(address(testUser)), 0);

        assertReserves(1500, 1000);

        assertEq(pair.totalSupply(), 1000);

        assertEq(

            token0.balanceOf(address(testUser)),

            10 ether + 0.5 ether - 1500

        );

        assertEq(token1.balanceOf(address(testUser)), 10 ether - 1000);

    }

        现在看起来完全不同了!我们现在损失了 0.5 ether 的 token0,相当于我们存入资金的 1/4 。这可是一笔不小的数目!

        想一想,是谁最终得到了这 0.5 个以太币:合约还是用户?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0xweb3q

有钱的捧个钱场,没钱的捧个人场

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值