1

i'm trying to create a smart contract which removes user's lp share from the pool doing these steps:

  1. calculates the current user's balance of LP tokens for a particular pair
  2. removes their liquidity from the pool and sends all the assets back to them
contract UniswapLiquidity {
    address UniswapV2Router = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    address UniswapV2Factory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
    address WETH = 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6;
    
    event Logs(string message, uint value);

    function removeLiquidity(
        address _tokenA,
        address _tokenB
    ) external returns (address pair) {
        //get pair address
        pair = IUniswapV2Factory(UniswapV2Factory).getPair(_tokenA, _tokenB);
        
        uint liquidity = IERC20(pair).balanceOf(msg.sender);

        //approve router to remove our liquidity token
        require(IERC20(pair).approve(address(this), liquidity));
        require(IERC20(pair).approve(UniswapV2Router, liquidity));

        (uint amountA, uint amountB) = IUniswapV2Router02(UniswapV2Router)
            .removeLiquidity(
                _tokenA,
                _tokenB,
                liquidity,
                1001, // 0, 1 or a calculation dont make any sense
                1001,
                msg.sender,
                block.timestamp + 20 seconds
            );

        emit Logs("amount A gotten", amountA);
        emit Logs("amount B gotten", amountB);
        emit Logs("Liquidity token burnt", liquidity);
    }
}

but im getting execution reverted due to ds-math-sub-underflow, though i tried different solutions, like extra approves and attempting to remove only 10% of the share using safemath, it didnt work out

2
  • Try running a simulation on tenderly and it will help you to find the exact reason for the r error. Commented Nov 28, 2023 at 14:49
  • 1
    it feels like it fails on IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair while msg.sender is being actually the smart contract's address instead of the user's wallet
    – Ivan
    Commented Nov 28, 2023 at 15:23

1 Answer 1

1

As you mention in your comment, it's likely failing when the router tries to transfer the LP tokens from your contract to the pair contract. In order for this to work, the user must set their own approval of the LP tokens to your smart contract prior to calling your contract. Then you use transferFrom to take the LP tokens from the user into your UniswapLiquidity contract. Then set the approval (as you are already doing) from the UniswapLiquidity contract to the router contract.

The require(IERC20(pair).approve(address(this), liquidity)); line can also be removed as the contract is just approving to itself, which isn't necessary

2
  • Thanks, this works! I actually tried to approve spending to the contract in a separate function inside the contract, but looks like this is impossible, cause the allowance doesnt change after that, so i just interacted directly from the wallet to the LP pair contract and it works now. Even though I send LP tokens to the contract, this doesnt mean the assets will go thru the contract, cause they (weth, erc20 token) are just sent to msg.sender, right?
    – Ivan
    Commented Nov 28, 2023 at 16:44
  • 1
    No problem, happy to help! That's correct. Since you're using msg.sender as the to parameter in the removeLiquidity function call, the underlying assets are sent directly from the pair contract to the user's account. They don't go through your contract
    – natewelch_
    Commented Nov 28, 2023 at 17:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.