ERC20 Integration Security Checklist

The article presents a list of ERC-20 integration issues that either arise from tokens not fully following the ERC-20 standard or implementing uncommon behaviors that might lead to security vulnerabilities.

1. Missing Return Values

There are ERC-20 tokens that do not return the boolean values for some functions. This might lead to undefined behaviour.

Missing return value on transfer functions

bool result = ERC20(token).transfer(recipient, amount);
require(result, "transfer failed");

This implementation will revert on tokens that do not return true on successful transfer.

TokensUSDT on Ethereum
BNB on Ethereum
OMG on Ethereum
BADGER on Ethereum
Example IssuesNotional Audit
PoolTogether Audit

Missing return value on some functions

The BNB token returns value on transferFrom but is does not do that for transfer function. This means that contracts that expect values being returned can pull BNB from the user’s account but cannot transfer it out.

TokensBNB on Ethereum
IssuesUniswap V1 Issue

Returning false on successful transfers

There are some tokens that a bool return for transfer(s) function, but then return false even when the transfer was successful.

Tokens– Used to be Gold Tether on Ethereum, but it has been updated.
IssuesVisor Finance Audit

Recommendation

It is recommended to use SafeERC20 library from OpenZeppelin that handle cases of transfer reverts and return values. However this will not handle tokens such as Gold Tether.

2. Approval Race Protection

There are some tokens that implemented it own protection against approval race issue which lead to even more complicated problems while integrating this tokens.

TokensUSDT on Ethereum
IssuesDuality Focus Audit

Recommendation

It is recommended to use OpenZeppelin’s forceApprove function. Another solution is to first execute approve with amount 0 and then another call with the desired approve amount.

3. Reentrant Calls

Some tokens implement the ERC-777 standard, which enables the execution of hooks during token transfers. ERC-777 utilizes ERC-1820, allowing users to register hooks for specific actions. It supports registering two types of hooks: one for sending tokens and another for receiving them.

Developers can register contracts implementing the ERC777TokensSender interface via ERC-1820 to execute code when tokens are sent. Similarly, contracts implementing the ERC777TokensRecipient interface can be registered to execute code upon receiving tokens.

However, this design introduces potential vulnerabilities to reentrancy exploits, where attackers could hijack the execution flow through registered hooks.

TokensimBTC on Ethereum
IssuesimBTC Uniswap Hack
Backed Protocol Audit

Recommendation

When integrating and supporting ERC-777 tokens, it is advised to follow the CEI (Checks-Effects-Interactions) pattern or to use a reentrancy guard to prevent ERC-777 tokens from reentering the contract logic.

4. Fee on Transfer

There are tokens that implement fee on transfer. That means the amount specified while executing transfer or transferFrom functions will not be the amount received by the recipient, but it will be reduced by the fee.

TokensSTA on Ethereum
PAXG on Ethereum
USDT on Ethereum (it is possible to enable fees)
USDC on Ethereum (it is possible to enable fees)
IssuesBalancer Pool with STA Deflationary Token Incident
Timeswap Audit

Recommendation

To support fee-on-transfer tokens, it is necessary to explicitly check the received amount of tokens by calculating the difference in token balances before and after the transfer. This ensures that only the received amount of tokens is used in the accounting logic.

5. Rebasing Tokens

There are rebasing tokens that modify balances outside of transfer functions. This leads to scenarios where the protocol’s accounting might be incorrect since the balance has rebased after the accounting event.

TokensstETH on Ethereum
OHM on Ethereum
AMPL on Ethereum
IssuesCally Audit
Agent Exchange Audit

Recommendation

There is no correct way of handling tokens that modify balances outside of transfers. It is recommended to use the wrapped ER20 tokens of the corresponding rebasing/airdrop tokens.

6. Multiple Token Addresses

There are tokens that have multiple addresses. This means it is possible to refer to the token’s accounting and approval mechanism through two different addresses, which might lead to serious issues for protocols that assume the token has a single address.

Tokens– Matic a native currency on Polygon has a corresponding ERC-20 token.
– In the past TrueUSD had two addresses but it has been upgraded since then.
IssuesTrueUSD Compound Vulnerability

Recommendation

While there is not a single correct way to support tokens with multiple token addresses, it is important for protocols to exercise caution in their accounting logic, especially when deploying to chains that have ERC-20 token representations of native currency.

7. Upgradable Tokens

Certain tokens are upgradable, enabling their owners to modify the token’s logic at any time. Changes to the token’s implementation can disrupt any smart contract that relies on its previous behavior.

TokensUSDT on Ethereum
USDC on Ethereum

Recommendation

Consider the ability of tokens being updated in the protocol threat modelling.

8. Flash Mintable Tokens

Some tokens support “flash minting”, allowing tokens to be minted for the duration of a single transaction, provided they are returned to the token contract by the end of the transaction. This is similar to a flash loan but does not require the tokens to exist before the transaction begins. A token capable of flash minting could potentially have a total supply of up to max uint256.

TokensDAI on Ethereum

Recommendation

Consider the ability of users to have high balance in the protocol threat modelling.

9. Tokens with Blocklists

Certain tokens implement an admin-controlled address blocklist at the contract level. If an address is blocked, transfers to and from that address are prohibited.

Malicious or compromised token owners can trap funds in a contract by adding its address to the blocklist. This can occur due to regulatory action against the contract itself, or against an individual user of the contract (e.g., a Uniswap liquidity provider), or it may be part of an extortion attempt targeting users of the blocked contract.

TokensUSDT on Ethereum
USDC on Ethereum
IssuesOpyn Audit

Recommendation

It is important to implement logic following the pull over push pattern to ensure that a single user will not be able to execute a denial-of-service attack effectively shutting down some or all functionality of the protocol.

10. Pausable Tokens

Some tokens can be paused by an admin. Similar to the blocklist issue, an admin-controlled pause feature exposes token users to risks from a malicious or compromised token owner.

TokensUSDT on Ethereum
USDC on Ethereum
ZIL on Ethereum

Recommendation

While there is not a single solution, it is important to note the ability of supported ERC-20 tokens to pause within the protocol’s threat model.

11. Low Decimals

Some tokens have low decimal precision. This can result in greater than expected precision loss.

TokensUSDT on Ethereum (6 decimals)
GUSD (Gemini USD) on Ethereum (2 decimals)
IssuesNumoen Audit

Recommendation

It is important not to assume that the ERC-20 token has 18 decimals and to evaluate all mathematical calculations to ensure they do not lead to a loss of precision.

12. High Decimals

Some tokens have more than 18 decimals. This can lead to unexpected reverts due to overflow, posing a liveness risk to the contract.

TokensYam-V2 on Ethereum (24 decimals)

Recommendation

It is important not to assume that the ERC-20 token has 18 decimals and to evaluate all mathematical calculations to ensure they do not lead to overflows given high number of decimals.

13. Use Of transferFrom By The Owner

Some token implementations do not decrease the caller’s allowance if the sender is the same as the caller, making transferFrom behave like transfer in this scenario. In contrast, other implementations do decrease the caller’s allowance from the sender in transferFrom, even if the caller and sender are the same address. This results in different semantics for transfer and transferFrom functions in such cases.

TokensDSToken Implementation

Recommendation

Ensure that the contract does not use transferFrom with the first argument provided by the user. A potential attacker could specify the contract’s own address as the argument and drain its balance.

14. No Revert on Failure

Some tokens do not revert on failure but instead return false. While this behavior technically complies with the ERC20 standard, it diverges from common Solidity coding practices.

TokensZRX on Ethereum
EURS on Ethereum
IssuesENS Audit

Recommendation

It is recommended to use SafeERC20 library from OpenZeppelin that handle cases of transfer reverts and return values.

15. Revert on Zero Value Approvals

Some tokens revert when approving a zero value amount. Integrators may need to implement special handling for this logic when working with such tokens.

TokensBNB on Ethereum

Recommendation

It is recommended to avoid implementing logic that would result in approving zero amount to the spender.

16. Revert on Approval To Zero Address

Some tokens revert when attempting to approve the zero address to spend tokens. Integrators may need to implement special handling for this scenario when working with such tokens.

TokensOpenZeppelin ERC20

Recommendation

It is recommended to avoid implementing logic that would result in approving zero address as a spender.

17. Revert on Transfer to the Zero Address

Some tokens revert when attempting to transfer to address(0). This can disrupt systems that rely on transferring tokens to address(0) to burn them.

TokensOpenZeppelin ERC20

Recommendation

It is recommended to avoid implementing logic that would result in transferring tokens to the zero address.

18. Revert on Large Approvals & Transfers

Some tokens (e.g., UNI, COMP) revert if the value passed to approve or transfer exceeds uint96. Both tokens handle a special case in their approve function where setting the allowance to type(uint96).max occurs if the approval amount is uint256(-1). This approach can potentially affect systems that depend on the exact value passed to approve being reflected in the allowances mapping.

TokensCOMP on Ethereum
UNI on Ethereum

Recommendation

In case the protocol is expected to support tokens that revert on large approvals and transfers, such as COMP or UNI tokens, it is important to ensure the protocol correctly handles scenarios involving large transfers and approvals.

19. Transfer of less than amount

Some tokens include a specific condition in their transfer functions where if amount == type(uint256).max, only the user’s balance is transferred. This can potentially create problems for systems that transfer a user-provided amount to their contract and then store the same value in their storage without verifying the actual amount transferred.

TokenscUSDCv3 on Ethereum
IssuesDYAD Audit

Recommendation

In case the cUSDCv3 tokens are expected to be supported it is important to validate the special case of transferring type(uint256).max and ensure its handled properly.

20. Permit Function That Do Not Follow ERC-2612

There are tokens that do not correctly implement ERC-2612 and its permit function. These tokens might not revert for incorrect signatures resulting in successful execution.

TokensDAI on Ethereum
RAI on Ethereum
– Other examples include GLM, STAKE, CHAI, HAKKA, USDFL, HNY
IssuesPoolTogether Audit

Recommendation

In case the permit functionality is expect to be supported it is important to carefully integrate tokens that do not correctly implement ERC-2612.

21. Non string metadata

Some tokens encode metadata fields (name / symbol) as bytes32 instead of the string format specified by ERC20. This can lead to challenges when attempting to use metadata from these tokens.

TokensMKR on Ethereum

Recommendation

It is recommended to either avoid using tokens’ names and symbols on-chain or creating correct adapter to handle tokens that returns bytes32 such as MKR. This is especially important since name, symbol and decimals are optional functions according to ERC-20 standard.

22. Frontend – Code Injection Via Token Name

Some tokens with malicious intent have been observed to embed harmful JavaScript within their name attribute. This enables attackers to potentially extract private keys from users who interact with these tokens through vulnerable frontends.

IssuesEtherDelta Issue

Recommendation

It is recommended to treat the ERC-20 token metadata as malicious and encode it correctly on the frontend.

References