I am developing a token using ganache/brownie. As the title says, if I try and use removeLiquidityETH to test removing liquidity tokens, for example like this

pair.approve(pair_address, lp_balance, {'from':accounts[0]})

router.removeLiquidityETH(my_token.address,lp_balance, 0,0, accounts[0], int(time.time())+60, {'from': accounts[0]})

Then I get an error IUniswapV2Router02.removeLiquidityETH confirmed (ds-math-sub-underflow)

and I do not see the ETH back in accounts[0].

However, looking at how removeLiquidityETH works I can implement each step manually

pair.approve(pair_address, lp_balance, {'from':accounts[0]})

pair.transferFrom(accounts[0], pair_address, lp_balance, {'from': pair_address})

tx = pair.burn(accounts[0], {'from': pair_address})
interface.IWETH(router.WETH()).withdraw(tx.events['Burn']['amount1'], {'from':accounts[0]})

And everything works as intended with my ETH and MyToken balances being transferred back to accounts[0].

I think the error is somewhere in approve or the transaction params {'from'} but I have tried every combination I can think of with pair.approve router.approve and my_token.approve and I still get the same error.

Does anyone have an example of how to use removeLiquidityETH properly? I have no issues with addLiquidityETH, in which I just use MyToken to approve the router spending.

2 Answers 2


From the docs

msg.sender should have already given the router an allowance of at least liquidity on the pool.

It doesn't seem like you're giving router an allowance to spend your liquidity tokens.

  • pair.approve(router_address, lp_balance, {'from':accounts[0]}) still fails
    – mch56
    Jul 4, 2021 at 22:20

I assume that accounts[0] is the address holding the LP tokens. The issue seems to be that you are approving the pair contract as spender of the LP tokens whereas you should be approving the router as spender.

Replace this:

pair.approve(pair_address, balance, {'from':accounts[0]})

By this:

pair.approve(router_address, lp_balance, {'from':accounts[0]})
  • This still fails. It fails in the transfer function - again it looks like the sender does not have enough balance to send; ie. the right approval has not been made.
    – mch56
    Jul 4, 2021 at 18:21
  • I just edited my answer. I replaced balance by lp_balance. If it stills does not work, please edit your question to include where you define all the variables that you use (pair_address, balance, lp_balance, router_address, etc.)
    – Undead8
    Jul 4, 2021 at 19:38
  • Apologies, this was a typo. The variable is lp_balance = pair.balanceOf(accounts[0]) ie. the balance of the lp tokens in accounts[0]. The issue is not with variable names, but with incorrect approval, though I don't understand why as I can follow the correct approval flow in the manual version/.
    – mch56
    Jul 4, 2021 at 22:18
  • If your variables are correct, I don't know what's the issue with the information you provided. Try to include more information. Maybe the error that you get and more of your code.
    – Undead8
    Jul 4, 2021 at 23:29
  • 1
    I solved it. I need to use the SupportingFeeOnTransferTokens variation of the removeLiquidityETH function. Out of interest do you know how to the uniswap front end knows which of the two (non-fee and supporting fee) functions it has to call when someone tries to remove liquidity on the website?
    – mch56
    Jul 5, 2021 at 19:02

Your Answer

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

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