# Weird Token List

ERC20 tokens are widely used in the Ethereum ecosystem, but not all tokens adhere strictly to the ERC20 standard. In this section, we will cover various unusual and unexpected behaviors of ERC20 tokens, illustrating real-world cases where these behaviors have been exploited. The goal is to help developers and auditors understand potential pitfalls when integrating or interacting with ERC20 tokens in smart contracts.

***

**Reentrant Calls**

Some tokens, such as ERC777 tokens, allow reentrant calls during transfers. This means that during a token transfer, an external call can be made back into the smart contract before the original transfer completes, which can lead to vulnerabilities. This behavior has been exploited, for instance, in the imBTC Uniswap pool, where reentrant calls led to drained funds.

**Example:** `Reentrant.sol`

***

**Missing Return Values**

Certain tokens do not return a boolean (`bool`) value from ERC20 methods as expected. Tokens like USDT, BNB, and OMG are examples of this. Some tokens, such as BNB, may return a boolean for some methods but fail to do so for others, which caused stuck tokens in Uniswap v1. In extreme cases, such as Tether Gold, tokens may declare a `bool` return type but always return `false` even when transfers are successful.

To handle this issue, a robust transfer abstraction (example provided) can help, though some tokens are impossible to handle consistently due to their broken implementations.

* **Example Tokens:**
  * `MissingReturns.sol`: Does not return a boolean for any ERC20 operation.
  * `ReturnsFalse.sol`: Always returns `false` for all ERC20 operations.

***

**Fee on Transfer**

Some tokens charge a fee on transfers, such as STA and PAXG. Even tokens that don't currently charge fees, like USDT or USDC, may introduce them in the future. These transfer fees can disrupt systems, such as when $500k was drained from Balancer pools due to the STA transfer fee.

**Example:** `TransferFee.sol`

***

**Balance Modifications Outside of Transfers (Rebasing / Airdrops)**

Certain tokens modify user balances without initiating a transfer. These include rebasing tokens like Ampleforth and airdrop models like Compound’s governance tokens. Such arbitrary balance changes can break systems that cache balances, like Uniswap V2 or Balancer. To prevent this, some systems ensure their pools are updated atomically during rebasing.

**Example:** A rebasing token implementation.

***

**Upgradable Tokens**

Tokens like USDC and USDT can be upgraded, allowing the contract owner to change the token's behavior at any time. This poses a risk to smart contracts that depend on specific behaviors from tokens. To mitigate this, developers can introduce logic that freezes interactions with an upgradable token if an upgrade is detected, as MakerDAO did with the TUSD adapter.

**Example:** `Upgradable.sol`

***

**Flash Mintable Tokens**

Tokens like DAI support "flash minting," allowing tokens to be minted for the duration of a single transaction, provided they are returned by the end of the transaction. This is similar to flash loans but without requiring pre-existing tokens. Such tokens could technically mint up to `max uint256` tokens within a single transaction.

Documentation for the MakerDAO flash mint module can be found here.

***

**Tokens with Blocklists**

Tokens like USDC and USDT implement admin-controlled blocklists that prevent transfers to or from certain addresses. This could be used to trap funds, for example, by adding a contract’s address to the blocklist. This risk may arise due to regulatory action or even malicious intent.

**Example:** `BlockList.sol`

***

**Pausable Tokens**

Tokens such as BNB and ZIL allow an admin to pause the token, preventing all transfers. This can expose users to risk if the admin is compromised or acts maliciously.

**Example:** `Pausable.sol`

***

**Approval Race Protections**

Some tokens, like USDT and KNC, do not allow increasing an approved amount (`M > 0`) if an existing amount (`N > 0`) is already approved. This is a protection against an ERC20 attack vector described here.

**Example:** `Approval.sol`

***

**Revert on Approval to Zero Address**

Tokens like those in the OpenZeppelin framework will revert if an attempt is made to approve the zero address to spend tokens. Developers may need to implement special logic to handle this behavior.

**Example:** `ApprovalToZeroAddress.sol`

***

**Revert on Zero Value Approvals**

Some tokens, such as BNB, revert when approving a zero-value amount. Integrators must account for this by adding special cases in their contract logic.

**Example:** `ApprovalWithZeroValue.sol`

***

**Revert on Zero Value Transfers**

Some tokens revert when a zero-value transfer is initiated.

**Example:** `RevertZero.sol`

***

**Multiple Token Addresses**

Some proxied tokens, particularly those with multiple addresses, pose unique risks. For example, a `rescueFunds` function could allow a contract owner to steal all tokens in a pool if the logic assumes a single token address per contract.

**Example:** `Proxied.sol`

***

**Low Decimals**

Tokens with fewer than 18 decimals, like USDC (which has 6), may introduce precision loss in calculations. Even more extreme, tokens like Gemini USD only have 2 decimals.

**Example:** `LowDecimals.sol`

***

**High Decimals**

Some tokens, such as YAM-V2, have more than 18 decimals (YAM-V2 has 24). This can cause overflows and introduce risks of unexpected reverts in smart contracts.

**Example:** `HighDecimals.sol`

***

**TransferFrom with src == msg.sender**

Some tokens, like DSToken, do not attempt to decrease the caller's allowance if the caller is also the sender, making `transferFrom` behave like `transfer`. In contrast, other tokens, like those using OpenZeppelin, always decrease the allowance.

**Examples:**

* `ERC20.sol`: Does not decrease allowance.
* `TransferFromSelf.sol`: Always decreases allowance.

***

**Non-String Metadata**

Tokens like MKR encode their metadata (e.g., name, symbol) as `bytes32` rather than `string`. This can lead to issues when attempting to read metadata.

**Example:** `Bytes32Metadata.sol`

***

**Revert on Transfer to the Zero Address**

Tokens, such as those based on OpenZeppelin’s implementation, revert when transferring to `address(0)`. This could disrupt systems relying on `address(0)` for burning tokens.

**Example:** `RevertToZero.sol`

***

**No Revert on Failure**

Some tokens, such as ZRX and EURS, return `false` rather than reverting on failure. This behavior, while technically compliant with ERC20, deviates from typical Solidity coding practices and may be overlooked by developers who forget to handle non-revert failures.

**Example:** `NoRevert.sol`

***

**Revert on Large Approvals & Transfers**

Tokens like UNI and COMP revert if the value passed to `approve` or `transfer` exceeds `uint96`. They also implement special logic for `approve` that sets allowances to `type(uint96).max` if the approval amount equals `uint256(-1)`.

**Example:** `Uint96.sol`

***

**Code Injection via Token Name**

Some malicious tokens include JavaScript code in their `name` attribute, allowing attackers to steal private keys from users interacting with the token via vulnerable frontends. This tactic has been used in the wild, notably to exploit EtherDelta users.

***

**Unusual Permit Function**

Certain tokens, such as DAI, RAI, GLM, and others, have a `permit()` function that does not follow EIP2612. Tokens without a proper `permit()` implementation may not revert, leading to unexpected execution of subsequent lines of code. Uniswap’s `Permit2` is a more compatible alternative for handling such tokens.

**Example:** `DaiPermit.sol`

***

**Transfer of Less Than Amount**

Tokens like cUSDCv3 contain special handling for transfers when `amount == type(uint256).max`, transferring only the user’s balance. Systems that transfer user-supplied amounts without verifying the actual transferred value may encounter issues with these tokens.

***

This section provides examples and insights into some of the common pitfalls smart contract developers face when interacting with ERC20 tokens. These behaviors can break smart contracts or lead to vulnerabilities if not accounted for properly. The provided examples illustrate these scenarios, encouraging caution and defensive programming practices.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/tutorial-44-weird-erc20-tokens/weird-token-list.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
