计算ERC20代币的买入/卖出税款

huangapple go评论62阅读模式
英文:

Calculate ERC20 token buy/sell tax

问题

我正在尝试实现一个计算代币购买/销售税的方法。开发人员在transfer()函数中实现了这个方法。

我已经进行了一些研究,有两种选项。

  1. eth_call - 模拟一个交换,计算差额。
  2. 在本地的Hardhat/Ganache上部署ERC20智能合约,执行交换并查看差额。

对我来说,eth_call似乎更好,但我遇到了一些问题。

 // 编码函数数据
const encodedData = router.interface.encodeFunctionData('swapExactETHForTokens', [
    0,
    path,
    to,
    deadline,
]);

// 使用eth_call获取amountsOut,执行模拟
const callResult = await this.provider.call({
    data: encodedData,
    value: parseUnits('2', 18),
    to: constants.UNISWAP_ROUTER_ADDRESS,
});

console.log('callResult', callResult);

// 解码结果
const decodedResult = router.interface.decodeFunctionResult(
    'swapExactETHForTokens',
    callResult
);

它不返回包括税费在内的实际金额,响应只是一个包含两个值的数组,第一个是ETH的数量,第二个是代币数量。如果我将amountIn设为0,那么我得到0%的税费,如果我增加它,那么代币的amountOut减少。

英文:

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.

答案1

得分: 1

你正在尝试猜测在Uniswap(或类似的交易所)上交换时会得到多少代币,但你还想在计算中包括任何转账费用。然而,你发现使用eth_call不总是能给出正确的答案。这是因为eth_call就像一次模拟运行 - 它不会进行任何实际的更改,所以它可能不会正确显示当代币有转账费用时会发生什么。

如果代币自动包含费用,那么从模拟调用中得到的结果将不会与实际交易结果匹配,因为eth_call不会模拟费用扣除。

以下是一些方法:

i 自行设置税率:如果你知道代币的税率且它不会更改,你可以从你的交换模拟结果中减去它。但请记住,如果代币合同更改其税率,这种方法可能会失效。

ii 在本地尝试:你可以部署合同到以太坊的本地版本,比如Ganache或Hardhat。然后你可以运行交换函数并查看余额变化。这可能会给你一个更准确的答案,但可能会更慢并需要更多资源。

iii 使用事件数据:一些代币合同生成的事件可能会有所帮助。例如,它们可能会生成一个包含实际转移的代币数量的Transfer事件,包括税费。

iiii 自己进行数学计算:如果税率是一个百分比,你可以首先计算不含税的代币数量,然后减去税费。

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);
  });
英文:

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);
  });

答案2

得分: 1

在研究之前,根据我的了解,使用eth_call来计算代币税可能并不完全可行,因为它实际上不会转移代币,所以你无法看到最终结果。虽然你可能可以使用web3.eth.call或进行一些涉及dexes的更复杂的调用,但我尚未验证这一点。

尽管如此,在研究过程中,我找到了一些地方和一个特定的博客声称可以做到这一点,但它非常复杂,复杂,并且在一个付费墙后面,所以我无法完全测试它,你可以查看并自行决定是否使用。

总的来说,我建议选项2,设置一个本地的hardhat/ganache。我提供了一段Python代码的链接,你可以基于它构建任何解决方案。

英文:

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

答案3

得分: 1

为了获得更准确的税收表示,您可能需要使用Uniswap V2 Router的getAmountsOut函数,而不是swapExactETHForTokens。 getAmountsOut旨在获取在给定输入金额和代币路径的情况下的预期输出金额。然后,您可以将估计的输出金额与交换后的实际输出金额进行比较,以确定税收。

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

// 用适当的值替换'tokenAmount'和'path'
const amountsOut = await uniswapV2Router.getAmountsOut(tokenAmount, path);

console.log('Estimated output amount:', amountsOut[amountsOut.length - 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]);

huangapple
  • 本文由 发表于 2023年7月24日 17:51:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76753283.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定