Burn and tax on ERC20 transfer

Hello, I’m trying to create a token with a burn (2.5%) function but also a tax (2.5%) that would go to an ethereum address of our choice. This burn/tax function would act on each transfers (to and from).
Could you explain to me how to code both togeher on the following contract please ?

pragma solidity ^0.5.0;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";


contract MYTOKEN is ERC20, ERC20Detailed {

    uint256 private _minimumSupply = 1000 * (10 ** 18);

    /**
     * @dev Constructor that gives msg.sender all of existing tokens.
     */
    constructor () public ERC20Detailed("MYTOKEN", "MTK", 18) {
        _mint(msg.sender, 15000 * (10 ** uint256(decimals())));
    }

    function transfer(address to, uint256 amount) public returns (bool) {
        return super.transfer(to, _partialBurn(amount));
    }

    function transferFrom(address from, address to, uint256 amount) public returns (bool) {
        return super.transferFrom(from, to, _partialBurn(amount));
    }

    function _partialBurn(uint256 amount) internal returns (uint256) {
        uint256 burnAmount = _calculateBurnAmount(amount);

        if (burnAmount > 0) {
            _burn(msg.sender, burnAmount);
        }
        return amount.sub(burnAmount);
    }

    function _calculateBurnAmount(uint256 amount) internal view returns (uint256) {
        uint256 burnAmount = 0;

        // burn amount calculations
        if (totalSupply() > _minimumSupply) {
            burnAmount = amount.mul(2.5).div(100);
            uint256 availableBurn = totalSupply().sub(_minimumSupply);
            if (burnAmount > availableBurn) {
                burnAmount = availableBurn;
            }
        }

        return burnAmount;
    }
}
1 Like

Hello @genesis24.

Before getting into your question, let me tell you that it’s not recommended to alter balances in that way. Most of DeFi protocols rely on the fact that if A has a balance of 100 and it sends 30 to B, A’ balance will be 70 after the transfer.

For protocols to support this kind of operation it would require (at least) one additional balanceOf call increasing the gas cost and making each transaction more expensive, which only gets worse at scale. This is why most protocols (e.g. Uniswap, Balancer) don’t support funny balance behaviors and just assume it works like I said.

Now, if you don’t care about integrating with existing protocols and you really want to do it anyway, I’d make sure to calculate the 2.5% before substracting anything (otherwise you’d be calculating 2.5% of the partially burned amount, which is less than the initial amount), and then have the _partialBurn and a _sendTax functions handle each 2.5% of the total amount.

1 Like

Hi @genesis24,

I suggest looking at Points to consider when creating a fungible token (ERC20, ERC777) for an example issue for a fee on transfer token.

I noticed that you were using openzeppelin-solidity, you should change to use the current name, @openzeppelin/contracts. See: https://docs.openzeppelin.com/contracts/3.x/#overview