Uniswap / v2-sdk

🛠 An SDK for building applications on top of Uniswap V2
https://uniswap.org/docs/v2/SDK/getting-started
MIT License
428 stars 1.09k forks source link

Support for "Fee On Transfer" tokens #131

Closed vladikopl01 closed 1 year ago

vladikopl01 commented 1 year ago

Is SDK support pairs with FOT tokens, or should I remake methods on my own?

Florian-S-A-W commented 1 year ago

Unfortunately not, if you try to use Pair.getOutputAmount the calculation would be wrong by the fee on transfer.

I tried calculating a trade with a Fee on Transfer token with the sdk and compared it with a result on Tenderly. I created a Pair using the SDK:

const chainId = 1
const CULT = new Token(chainId, "0xf0f9D895aCa5c8678f706FB8216fa22957685A13", 18)
const WETH = WETH9[chainId]
const pairAddress = "0x5281E311734869C64ca60eF047fd87759397EFe6"
const pairContract = new ethers.Contract(pairAddress, uniswapV2poolABI, wallet)

async function createSDKPair() {

    const reserves = await pairContract["getReserves"]()
    let wethAmount = CurrencyAmount.fromRawAmount(WETH, reserves[0])
    let cultAmount = CurrencyAmount.fromRawAmount(CULT, reserves[1])
    const fotPair = new Pair(wethAmount, cultAmount)

    return fotPair
}

I then queried the output amount of a swap and also swapped the corresponding amount on a Tenderly testnet:

async function compareSDKWithOnChainResult() {

    const sdkPair = await createSDKPair()

    const tradeAmount = CurrencyAmount.fromRawAmount(WETH, ethers.utils.parseEther("1.0"))

    const sdkOutput = sdkPair.getOutputAmount(tradeAmount)[0]
    console.log("Output from SDK: " + sdkOutput.toSignificant(18))

    let wethContract = new ethers.Contract(WETH.address, erc20abi, wallet )
    const routerContractAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
    let routerContract = new ethers.Contract(routerContractAddress, uniswapV2RouterABI, wallet)
    await wethContract["approve"](routerContractAddress, ethers.utils.parseEther("1.0"))

    let res = await routerContract["swapExactTokensForTokensSupportingFeeOnTransferTokens"](ethers.utils.parseEther("1.0"), 1, [WETH.address, CULT.address], wallet.address, Date.now() + 60000, {gasLimit: 10000000}) 
}

The output here was 367043830.509396967 Comparing that with the actual swap: Screenshot 2023-04-27 at 12 43 32

We see that 0.4% of the output has been transferred to the DAO. Please note that the SDK accounts for the decimals of the token, Tenderly doesn't. The calculation of the SDK is correct but it doesn't account for the fee that happens after the exchange.

vladikopl01 commented 1 year ago

@Florian-S-A-W Thanks a lot for the explanation and code examples