In this post, we describe different transfer fee features that apply to ERC-20 tokens, how they are beneficial for the token governance and what kind of gotchas there can be. We also introduce the token tax data point feature that is now available for all trading pairs listed on Trading Strategy.
What is token tax?
A “token” tax is a term often used to describe tokens with transfer fees that cause deflation or redistribute trade profits to the protocol development:
- Each time a token is transferred, some transferred amount is burned, redirected to a development fund or otherwise “taxed”.
- Token tax is usually paid by the originator wallet that initiates the transfer. The tax is taken from the sent amount during the transfer: initiated transfer amount > received transfer amount.
- Token tax may also reduce the token supply, thus creating deflationary tokens. The deflationary assumption comes from the economic theory that by reducing the supply, the value of the goods should go up. The most famous cryptocurrency having such deflationary mechanics is Ethereum and its EIP-1559 burning mechanism.
- Token tax can redirect some of the transfer and trading fees to the protocol development fund. This can guarantee sustainable protocol development outside any initial fundraising.
- Usually, the token tax term is not used for the native gas token on a blockchain, like Ether (ETH) on Ethereum, where any transfer fee is considered to be a natural part of the core protocol. The token tax term applies to ERC-20-like tokens that historically have lacked transfer fee features. There is no terminology standard, so different terms are applied in different contexts.
- Different % amounts of “taxes” may apply to different types of transactions like buy, sell, and treasury management.
Here we use the terms deflationary and inflationary in a technical protocol context. Although Bitcoin is claimed to be deflationary, it is currently inflationary and is going to be “non-inflationary” after all 21 million coins have been mined. Bitcoin protocol does not burn, redirect or otherwise reduce supply of bitcoins on transfers.
Transfer fee and funding the development
Token tax is one mechanism to attempt to create more sustainable tokenomics (token economies), where some of the fees captured from token transfers are redirected to the protocol revenue and development.
The most successful taxed token has been ZCash with its “Founder reward”:
- 80% of the ZCash transaction fee went to miners.
- 20% of the ZCash transaction fee went to the founders (Electric Coin co.), to offset the cost of developing the protocol.
Instead of raising a large amount of capital upfront to support the software development related to ZCash, the development was funded from stable revenue streams of the protocol. The founder reward mechanism was controversial in the cryptocurrency community.
Encouraging long term investing with token taxes
Many deflationary tokens have strong “ponzinomics” - even though they are not true ponzis by the definition of a ponzi. The tokenomics are designed to discourage short-term speculation and encourage long-term investing.
Issues with transfer fees on ERC-20 like tokens
All native gas tokens on blockchains are “taxed”. E.g. when you transfer ETH on Ethereum mainnet, some of the ETH gets burnt in the transaction or given to the block producers.
Today, the concept of a transfer fee has not taken off outside the native gas tokens. For example, because of accounting difficulties with taxed token taxes, listing them on centralized exchanges is problematic. Note that such limitations do not apply to decentralised exchanges (DEXes) that are built to account for such features and this is why taxed tokens are listed on DEXes only.
Most taxed tokens rely solely on tokenomics for their success and lack fundamental value creation and innovation. This makes them more Ponzi like as it is often hard to see at which point the ecosystem could turn sustainable. However, there is no particular reason why a token tax could not work well for a legit project.
Token tax-based projects often have anonymous teams and weak governance. Usually, the token tax rate can be updated by the governance. Sometimes rogue dev teams flip the token tax to 100% creating a so-called honeypot and causing a project rug pull.
Despite all the issues. some taxed tokens had limited success, usually before failing for a reason outside the tokenomics. Tax on tokens could be one of the keys to long-term sustainable development. For example, Elephant Money was doing ok before they had an incident with flash loans allowing attackers to get away with $11M.
Honeypots and other “rug pull” risks
As token tax amounts may be customised freely, sometimes this feature is exploited to launch hostile tokens to markets. These hostile tokens are called honeypots.
Honeypots are tokens that are baiting unsuspecting users and algorithms to buy them. These tokens have promising OHLCV data to make it look like an attractive buy from a technical analysis perspective, like artificially created token price pumps. After buying the token, a user cannot sell it for profit.
Honeypots include, but are not limited to
- Non-transferable tokens like JustHoldIt- buy transaction is the only whitelisted transfer.
- Tokens with 100% or high (>40%) sell tax, making tokens effectively unsellable for profit.
- Other impossible sell conditions to meet, like one on JUMPN
A word of warning: If you lose money by buying a honeypot token, you will not get your money back.
Token tax data on Trading Strategy
Trading Strategy includes token tax and deflation data as a part of its datasets.
Data is collected by a trading pair, not by a token, because different taxes may apply to transactions based on the underlying activity. Most taxed tokens have the same flat tax across all transfers, but this is not always the case. For example, different liquidity pools have different addresses, and thus the coded token tax can differ between these pools.
Token tax data is available at
- Trading Strategy website: See Token tax entry for each trading pair
- Real-time APIs: See PairDetails structure
- Backtesting datasets:
See tradingstrategy.pair
Python module for data details. See the token tax documentation for real-time and backtesting examples on transfer fees.
Transfer fees presentation
Trading Strategy measures token transfer fees in different life cycles of token trading.
Trading Strategy presents transfer fees in the format of:
buy tax % / transfer tax % / sell tax %
E.g.
5% / 5% / 5%
Warning
Token tax measurements are not real-time. There are no guarantees that tokens with bad governance won’t change their tax structure, creating a honey pot and effective rug pull. Never trade taxed tokens unless you are willing to lose all of your capital.
Token tax examples
Here are some examples of different token taxes:
- Example of a taxed trading pair: ELEPHANT-BUSD on PancakeSwap - 10% tax
- Example of a non-taxed trading pair: BNB-USDT on PancakeSwap - no fees
- Example of a token with buy and sell tax, but no transfer tax: DHOLD-ETH on Uniswap - taxed 10%/0%/10%
- Example of a honeypot trading pair: JST-BNB - In practice, one cannot sell Jump Satoshi token and it can be considered as a honeypot. Even if the fact that it is in practice unsellable is disclosed in the whitepaper, the token smart contract source code is obfuscated. The BSCScan comment section is filled wiht angry users.
- Example of too low liquidity trading pair: Omega Protocol Money-ETH on Uniswap - cannot measure tax because there is not enough liquidity to trade
Development of deflationary tokens
ERC-20 tokens do not have a clean interface to describe transfer fee behaviour.
A transfer fee is usually implemented as a complicated ERC-20 _transfer() function that checks for various whitelisted addresses and then constructs a fee for the transfer based on logic.
Example of a Solidity code for a token with transfer tax:
function _transfer(
address from,
address to,
uint256 amount
) private {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(amount > 0, "Transfer amount must be greater than zero");
// is the token balance of this contract address over the min number of
// tokens that we need to initiate a swap + liquidity lock?
// also, don't get caught in a circular liquidity event.
// also, don't swap & liquify if sender is uniswap pair.
uint256 contractTokenBalance = balanceOf(address(this));
bool overMinTokenBalance = contractTokenBalance >= numTokensSellToAddToLiquidity;
if (
overMinTokenBalance &&
!inSwapAndLiquify &&
from != uniswapV2Pair &&
swapAndLiquifyEnabled
) {
contractTokenBalance = numTokensSellToAddToLiquidity;
//add liquidity
swapAndLiquify(contractTokenBalance);
}
//indicates if fee should be deducted from transfer
bool takeFee = true;
//if any account belongs to _isExcludedFromFee account then remove the fee
if(_isExcludedFromFee[from] || _isExcludedFromFee[to]){
takeFee = false;
}
//transfer amount, it will take tax, burn, liquidity fee
_tokenTransfer(from,to,amount,takeFee);
}
//this method is responsible for taking all fee, if takeFee is true
function _tokenTransfer(address sender, address recipient, uint256 amount,bool takeFee) private {
if(!takeFee)
removeAllFee();
if (_isExcluded[sender] && !_isExcluded[recipient]) {
_transferFromExcluded(sender, recipient, amount);
} else if (!_isExcluded[sender] && _isExcluded[recipient]) {
_transferToExcluded(sender, recipient, amount);
} else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
_transferStandard(sender, recipient, amount);
} else if (_isExcluded[sender] && _isExcluded[recipient]) {
_transferBothExcluded(sender, recipient, amount);
} else {
_transferStandard(sender, recipient, amount);
}
if(!takeFee)
restoreAllFee();
}
function _transferStandard(address sender, address recipient, uint256 tAmount) private {
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity) = _getValues(tAmount);
_rOwned[sender] = _rOwned[sender].sub(rAmount);
_rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
_takeLiquidity(tLiquidity);
_reflectFee(rFee, tFee);
emit Transfer(sender, recipient, tTransferAmount);
}
Trading Strategy is an algorithmic trading protocol for decentralised markets, enabling automated trading on decentralised exchanges (DEXs). Learn more about algorithmic trading here.
Join our community of traders and developers on Discord.