Section 15 of 16

Build
+15 Lynx

Router: Fee-on-Transfer Support

What You Are Building

Some ERC-20 tokens deduct a fee on every transfer. When you send 100 tokens, the recipient might only receive 98. The original USDT, deflationary tokens, and many "rebase" tokens behave this way.

The standard swap functions from the previous section assume the full amount arrives at the pair. They pre-calculate the exact output using getAmountOut. But if 2% disappears during the transfer, the math breaks. The pair would try to send more output than the constant product formula allows, and the swap would revert.

Uniswap V2 Router02 solves this with a separate set of swap functions that do not pre-calculate amounts. Instead, they measure the actual balance after each transfer to determine the real input.

_swapSupportingFeeOnTransferTokens

This is the alternative to _swap(). Instead of using a pre-calculated amounts array, it reads the pair's actual token balance at each hop:

  1. For each hop, get the pair's reserves.
  2. Read the pair's current balance of the input token.
  3. Calculate amountInput = balance - reserveInput. This is the actual amount that arrived, after any transfer fee.
  4. Use getAmountOut(amountInput, reserveIn, reserveOut) to calculate the output for this hop.
  5. Determine the swap direction and call pair.swap().

The key difference: the standard _swap() trusts the pre-calculated amounts array. The FOT version trusts the actual on-chain balance. This makes it work with any token, regardless of transfer behavior.

FOT Swap Variants

Three external functions use the FOT-safe internal swap:

swapExactTokensForTokensSupportingFeeOnTransferTokens: Transfers input tokens to the first pair, calls the FOT swap, then checks that the recipient's final balance increased by at least amountOutMin. It cannot use getAmountsOut to predict the output, so it measures the recipient's balance before and after.

swapExactETHForTokensSupportingFeeOnTransferTokens: Wraps ETH, deposits WETH to the first pair, runs the FOT swap, and validates the recipient's output balance.

swapExactTokensForETHSupportingFeeOnTransferTokens: Runs the FOT swap with the Router as recipient, measures the WETH received, unwraps it, and sends ETH to the user.

Notice there are no "exact output" FOT variants. You cannot guarantee an exact output when fees are unpredictable.

FOT-Safe Liquidity Removal

removeLiquidityETHSupportingFeeOnTransferTokens: Similar to removeLiquidityETH, but instead of trusting the returned amountToken, it measures the Router's actual token balance after the burn. This handles tokens that take a fee on the transfer from the pair to the Router.

removeLiquidityETHWithPermitSupportingFeeOnTransferTokens: Adds permit support to the FOT-safe liquidity removal.

Library Wrapper View Functions

The Router also exposes the Library's calculation functions as public view functions so external contracts and frontends can call them without importing the library directly: quote, getAmountOut, getAmountIn, getAmountsOut, and getAmountsIn. Each simply delegates to UniswapV2Library.

Your Task

Implement the FOT-safe swap internal function, all five FOT external functions, and the five library wrapper view functions. The starter code provides the function signatures and the infrastructure from previous sections.

Your Code

Solution.sol
Solidity
Loading editor...

Requirements

FOT swap reads actual balance instead of pre-calculated amounts
FOT swap calculates amountInput from balance minus reserve
FOT swap uses getAmountOut for each hop
FOT swap determines direction using token0
FOT tokens swap checks balance before and after
FOT tokens swap validates output via balance difference
FOT ETH swap validates WETH path
FOT ETH output reads WETH balance
FOT liquidity removal uses actual token balance
FOT liquidity permit calls removeLiquidityETHSupportingFeeOnTransferTokens
Library wrapper: quote delegates to UniswapV2Library
Library wrapper: getAmountsOut delegates to UniswapV2Library
Library wrapper: getAmountsIn delegates to UniswapV2Library
No pre-calculated amounts array in FOT swap