3

I am trying to implement a method for calculating token buy/sell tax. The one that devs implement it in the transfer() function.

I've done some research and there are 2 options.

  1. eth_call - simulate a swap, calculate the difference
  2. deploy the ERC20 smart contract on a local hardhat/ganache, execute swap and see the difference

The eth_call seems to be better for me but I'm facing some issues.

 // Encode function data
        const encodedData = router.interface.encodeFunctionData('swapExactETHForTokens', [
            0,
            path,
            to,
            deadline,
        ]);

        // Get amountsOut using eth_call, performs a SIMULATION
        const callResult = await this.provider.call({
            data: encodedData,
            value: parseUnits('2', 18),
            to: constants.UNISWAP_ROUTER_ADDRESS,
        });

        console.log('callResult', callResult);

        // Decode result
        const decodedResult = router.interface.decodeFunctionResult(
            'swapExactETHForTokens',
            callResult
        );

it does not return the actual amount including taxes, the response is just an array of the amounts out first is amount of ETH and second is the token amount. if I set the amountIn 0, then I get 0% tax, if I increase it then the amountOut of token decreases.

kakakakakakakk
  • 467
  • 10
  • 31
  • [You can find an example of token tax calculation here](https://web3-ethereum-defi.readthedocs.io/api/uniswap_v2/_autosummary_uniswap_v2/eth_defi.uniswap_v2.token_tax.estimate_token_taxes.html#eth_defi.uniswap_v2.token_tax.estimate_token_taxes). Please see the source code for the details. – Mikko Ohtamaa Jul 24 '23 at 11:26
  • @MikkoOhtamaa this is cool but I would like to have my own js implementation, and I'm still researching on `eth_call` – kakakakakakakk Jul 24 '23 at 12:39
  • There should be ways to do it with eth_call, but my understanding is its fairly complicated. You maybe better off with option two, in which case you have an example of what it would look like in python with that token tax collector link that was commented by Mikko – Lucas Hendren Aug 01 '23 at 07:05
  • solved it using second option – kakakakakakakk Aug 07 '23 at 11:33

3 Answers3

1

You're trying to guess how many tokens you'll get when you swap on Uniswap (or something like it), but you also want to include any transfer fees in your calculations. However: you've found that using an eth_call doesn't always give you the right answer. This is because eth_call is like a practice run - it doesn't make any actual changes, so it may not correctly show what happens when tokens have a transfer fee.

If the token includes a fee automatically, the result from a practice call won't match the real transaction result, since the eth_call doesn't practice the fee deduction.

Here are a few approaches:

i Set the tax rate yourself: If you know the token tax rate and it doesn't change, you could just subtract it from your swap simulation result. But remember, this could break if the token contract changes its tax rates.

ii Try it out locally: You could deploy the contract to a local version of Ethereum, like Ganache or Hardhat. Then you could run the swap function and look at the balance changes. This could give you a more accurate answer, but it might be slower and need more resources.

iii Use event data: Some token contracts produce events that could help. For example, they might make a Transfer event with the actual number of tokens transferred, including the tax.

iiii Do the math yourself: If the tax is a percentage, you could first calculate the amount of tokens received without tax and then subtract the tax.

const { ethers } = require("hardhat");

async function main() {
  const Token = await ethers.getContractFactory("yourToken");
  const token = await Token.deploy();
  await token.deployed();
  
  const initialBalance = await token.balanceOf(account);

  // Swap
  await token.swapExactETHForTokens(...args);
  
  const finalBalance = await token.balanceOf(account);

  // The difference is the amount of tokens received, accounting for tax
  const actualTokensReceived = finalBalance.sub(initialBalance);

  console.log('Tokens received:', ethers.utils.formatUnits(actualTokensReceived, 'ether'));
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

1

Prior to researching this, to my knowledge it wasnt fully possible to use eth_call to calculate the token tax because it doesnt actually transfer the token so you cant see the final result. Though you maybe able to use web3.eth.call or do some more complicated calls involving dexes but i have not verified this yet.

That being said, while researching it I came across a few places and a specific blog that have claimed to do it but its very complicated, complex and behind a paywall so I was not able to fully test it, you can take a look and use at your discretion

Overall I would suggest option 2, setting up a local hardhat/ganache. Im providing a link to code in python that you can use to base any solution off of

Lucas Hendren
  • 2,786
  • 2
  • 18
  • 33
1

To get a more accurate representation of the tax, you might need to make use of the Uniswap V2 Router's getAmountsOut function instead of swapExactETHForTokens. getAmountsOut is designed to get the expected output amounts given an input amount and the token path. You can then compare the estimated output amount with the actual output amount after the swap to determine the tax.

const uniswapV2Router = new ethers.Contract(
  constants.UNISWAP_ROUTER_ADDRESS,
  ['function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)'],
  this.provider
);

// Replace 'tokenAmount' and 'path' with appropriate values
const amountsOut = await uniswapV2Router.getAmountsOut(tokenAmount, path);

console.log('Estimated output amount:', amountsOut[amountsOut.length - 1]);
Uğur Özpınar
  • 1,033
  • 7
  • 16