How Fee-on-Transfer Tokens Impact Smart Contract Accounting

Smart contracts are essential in the blockchain world, enabling automated and trustless transactions. However, security in smart contracts is crucial to protect user assets and maintain trust in decentralized systems. One specific challenge that smart contracts face is dealing with fee-on-transfer tokens. In this article, we will explore why smart contract security is important and how fee-on-transfer tokens can affect transactions.

Understanding Smart Contract Security

Why is Smart Contract Security Important?

  1. Irreversibility of Transactions: Blockchain transactions cannot be undone once confirmed. Any vulnerabilities or bugs in a smart contract can lead to permanent financial losses.

  2. Financial Stakes: Smart contracts often handle large amounts of money. Security flaws can result in significant monetary losses for users and businesses.

  3. Trust and Adoption: The success of blockchain technology relies on trust. If smart contracts are insecure, users and investors may lose confidence, slowing the technology's growth and adoption.

  4. Autonomous Execution: Smart contracts execute automatically based on predefined conditions. If these conditions are not secure, malicious actors can exploit them to perform unintended actions.

  5. Interoperability: Smart contracts often interact with other contracts and protocols. A vulnerability in one contract can compromise interconnected systems.

The Fee-on-Transfer Issue

What are Fee-on-Transfer Tokens?
Fee-on-transfer tokens are designed to take a small fee whenever they are transferred from one wallet to another. This fee can be used for various purposes such as funding development, providing liquidity, or burning tokens to reduce supply.

How Fee-on-Transfer Tokens Affect Transactions

Incorrect Amounts Received
When a fee is deducted during the transfer of tokens, the receiving smart contract may end up with fewer tokens than expected. This can cause the transaction to fail or result in logical errors within the contract.

Example Scenario:
  • Alice wants to buy an item costing 100 tokens.
  • She transfers 100 tokens to the smart contract.
  • Due to a 10% fee, only 90 tokens are received by the contract.
  • The contract, expecting 100 tokens, fails the transaction.

Accounting Errors
Smart contracts often maintain internal balances based on token transfers. If the fee is not accounted for, the contract's internal accounting can become inconsistent with actual token balances, potentially leading to exploits.

Example Scenario:
  1. A decentralized exchange (DEX) expects 100 tokens but receives only 90 due to a fee.
  2. The DEX credits the user with 100 tokens' worth of the swapped asset, causing an accounting discrepancy and potential financial loss.

Explaining Fee-on-Transfer to an 8-year Old

Let's imagine you have a piggy bank, and every time you move some of your coins to another piggy bank, a few coins disappear as a fee. Now, if you want to give 10 coins to your friend, but 2 coins disappear during the transfer, your friend will only get 8 coins.
In the world of blockchain, some special tokens work like this piggy bank example. When you send these tokens to someone else, a small fee is taken out. This means the person you’re sending the tokens to will receive a bit less than you intended.
The problem for smart contracts is that they might not expect this fee. So, if the contract thinks it's getting 10 tokens but only gets 8, it can get confused and make mistakes.
To avoid this, smart contracts need to be smart enough to check how many tokens actually arrived after the fee is taken out, and then adjust their calculations so everything works correctly.

Example Scenario for Fee-on-Transfer

Imagine we have a smart contract that handles a game where players can buy virtual items. In this game, you use a special token called "GameToken" to buy items. Each GameToken transfer has a 10% fee.

Here’s a simple scenario:

  1. Player's Action: Alice wants to buy a virtual sword that costs 100 GameTokens.

  2. Token Transfer with Fee: When Alice sends 100 GameTokens to the game's smart contract, a 10% fee is applied. So, instead of the contract receiving 100 tokens, it actually receives 90 tokens (because 10 tokens are taken as a fee).

  3. Contract Expectation: The smart contract expects to get 100 tokens to complete the purchase, but it only gets 90 tokens due to the fee.

  4. Resulting Issue: The smart contract might:

    • Fail the transaction because it didn't receive the expected 100 tokens.
    • Credit Alice with the sword even though only 90 tokens were received, causing an accounting error and potential loss of tokens for the game.
function buySword(player, amount) {
    const swordCost = 100;

    // Transfer GameTokens from player to contract
    transferFrom(player, thisContract, amount);

    // Check if the contract received the correct amount
    if (amount >= swordCost) {
        // Grant the sword to the player
    } else {
        // Revert transaction or handle the error
        revert("Not enough tokens to buy the sword");

What Goes Wrong

  1. Alice Sends Tokens: Alice calls buySword(player = Alice, amount = 100).

  2. Fee Applied: 10 tokens are taken as a fee, so the contract only receives 90 tokens.

  3. Contract Confusion: The contract checks if amount >= swordCost, but the actual amount received is only 90, not 100.

  4. Transaction Fails: The contract might fail the transaction with an error message "Not enough tokens to buy the sword".
Fixing the Issue
To fix this, the contract should check the actual balance received rather than the amount sent:

function buySword(player, amount) {
    const swordCost = 100;

    // Initial balance of the contract
    const initialBalance = getBalance(thisContract);

    // Transfer GameTokens from player to contract
    transferFrom(player, thisContract, amount);

    // Actual balance after the transfer
    const finalBalance = getBalance(thisContract);

    // Calculate the actual received amount
    const receivedAmount = finalBalance - initialBalance;

    // Check if the contract received the correct amount
    if (receivedAmount >= swordCost) {
        // Grant the sword to the player
    } else {
        // Revert transaction or handle the error
        revert("Not enough tokens to buy the sword");

By checking the actual balance before and after the transfer, the smart contract can correctly handle fee-on-transfer tokens and avoid the issues caused by unexpected fees.

Mitigating the Fee-on-Transfer Vulnerability

Best Practices for Developers

  1. Check Received Amounts: Always verify the actual amount of tokens received after a transfer instead of assuming the full amount was transferred.

  2. Update Internal Accounting: Adjust the contract's internal balances to reflect the actual received amount after accounting for any fees.

  3. Use Safe Transfer Functions: Utilize token standards and safe transfer functions that handle fee-on-transfer tokens appropriately.

  4. Explicit Handling: Explicitly handle known fee-on-transfer tokens within the contract's logic to ensure accurate accounting and avoid vulnerabilities.

Smart contract security is fundamental to the integrity, reliability, and trustworthiness of blockchain ecosystems. The fee-on-transfer issue highlights the need for careful handling of token transfers to ensure contracts perform as intended. By adopting best practices and robust security measures, developers can protect user assets, maintain trust, and support the sustainable growth of blockchain technology.

You might also be interested in:

About Truscova:
Truscova comes with 30+ years of academic research and hundreds of academic publications which pioneered the area of Formal Verification. The team combines academic leadership, industrial strength and Blockchain expertise. Truscova currently analyzes Solidity code combining Formal Verification techniques: abstract interpretation, constraint solving, theorem proving, and equivalence checking.

Ready To Take
The Next Step?

Contact Us


Truscova GmbH
Bremen | Germany

Social Media

©2022 | Imprint & Privacy Policy