Analise smart-contract
07.08.2024

Understanding Common ERC-20 Smart Contract Errors in Solidity

Smart contracts in the Ethereum ecosystem often contain intricate logic to ensure the security and functionality of decentralized applications. However, errors can arise due to various reasons, leading to failed transactions and potential vulnerabilities. This blog post will explore some common errors encountered in ERC-20 token transactions, their causes, and solutions.

1. Pancake: K

The error occurs if the invariant ‘the product of reserves must be constant’ is violated. This condition guarantees that after the swap is executed, the new product of reserves (including commissions) will not be less than the old product. A violation of this condition can occur if:

  1. The tokens entered into the pool (amount0In or amount1In) do not match the expected values according to the invariant formula. There was an error in calculating balances after swap.
  2. Someone tried to manipulate the pool, which caused the token balances to change, bypassing the standard swap process.
  3. If this condition is not met, the ‘Pancake: K’ error is raised, signalling a mathematical invariant violation.

An invariant violation means that one of the fundamental conditions that ensure correct operation of the system is no longer fulfilled. In the context of decentralised exchanges such as PancakeSwap, the invariant is usually associated with a mathematical equation that must remain true in order to maintain the balance between token reserves in the liquidity pool.


require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(10000**2), 'Pancake: K');

Solution:
Check that the pool has enough liquidity to perform the exchange and that the values do not exceed the reserves (_reserve0, _reserve1). Continuously monitor the pool reserves and take steps to replenish them if necessary.

2. TransferHelper: TRANSFER_FROM_FAILED

This error signifies a failed token transfer using the safeTransferFrom method, which is a common pattern for securely transferring ERC-20 tokens.


function safeTransferFrom(address token, address from, address to, uint value) 
  internal {
    // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
    (bool success, bytes memory data) = 
token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
    require(success && (data.length == 0 || abi.decode(data, (bool))), 
'TransferHelper: TRANSFER_FROM_FAILED');
  }

Cause:

  1. The from address has not granted or has not granted enough permissions for msg.sender address to transfer tokens (allowance, approve).
  2. Address from does not have enough tokens to perform the transfer. This may also be due to the fact that token administrators have the ability to modify the token balance and at the time of withdrawal the user who made the investment may not have enough balance to perform the withdrawal.
  3. The token contract may not implement the transferFrom function or implement it incorrectly.
  4. The token contract may contain additional checks or restrictions in the transferFrom function, which may cause the transaction to be cancelled.
  5. If there is not enough gas to execute the transaction, the transaction may fail.

Solution:

  1. Make sure that the from address has granted enough allowance for msg.sender. This can be done by calling the token contract's allowance function.
  2. Make sure that the from address has enough tokens to perform the translation.
  3. Verify that the token contract address is correct and that the contract is ERC-20 compliant.
  4. Check the implementation of the transferFrom function in the token contract. Make sure it is implemented correctly and does not have any additional constraints that could cause a failure.
  5. Try increasing the gas limit when calling the transaction to make sure the problem is not a lack of gas.

3. INSUFFICIENT_LIQUIDITY

This error occurs when attempting to withdraw more liquidity than is available in the reserves of a liquidity pool.


(uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
        require(amount0Out < _reserve0 && amount1Out < _reserve1, 'Pancake:
INSUFFICIENT_LIQUIDITY');

Cause:

  1. The liquidity pool does not contain sufficient amount of one or both tokens to fulfil the requested exchange.
  2. The requested amount of tokens for withdrawal (amount0Out or amount1Out) exceeds the available number of tokens in the pool.
  3. Mismatch between the reserves in the contract and the actual state of the pool. The reserves stored in the contract may not match the actual balance state of tokens in the pool due to errors or manipulation.

Solution:

  1. Check the pool reserves and make sure they are sufficient to fulfil the requested exchange. This can be done using the getReserves function.
  2. Make sure that the amount0Out and amount1Out parameters are correct and do not exceed the available number of tokens in the pool.
  3. Make sure that the reserves in the contract match the actual token balance. To do this, you can add checking and updating reserves before performing the exchange.

INSUFFICIENT_LIQUIDITY

4. APPROVE_FAILED

The `APPROVE_FAILED` error occurs during the execution of the `safeApprove` function. This function is designed to set the amount of tokens that an owner allows a spender to use on their behalf.


function safeApprove(address token, address to, uint value) internal {
  (bool success, bytes memory data) = 
token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
  require(success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper: APPROVE_FAILED');
}

Cause:

  1. The token contract might not have the `approve` function or it might be incorrectly implemented.
  2. There might be an issue with the token contract’s state, such as insufficient balance or allowance.
  3. The `approve` function could revert for security reasons implemented in the token contract.

Solution:

  1. Ensure that the token contract conforms to the ERC-20 standard and includes a properly implemented `approve` function.
  2. Check the token contract's state and ensure that the account has enough tokens to approve.
  3. Verify that the address and amount passed to the `safeApprove` function are correct.
  4. Debug further by checking the specific error message or reason for the revert in the token contract.

5. Fail with error 'ds-math-sub-underflow'

The `ds-math-sub-underflow` error is thrown when a subtraction operation underflows, i.e., when the result of the subtraction is less than zero.


    function sub(uint x, uint y) internal pure returns (uint z) {
      require((z = x - y) <= x, 'ds-math-sub-underflow');
    } 

Cause:
This error occurs because the subtraction operation `x - y` results in a negative number, which is not allowed for unsigned integers in Solidity.

Solution:

  1. Ensure that the value of `y` is always less than or equal to `x` before performing the subtraction.
  2. Implement checks in your code to handle cases where `y` might be greater than `x` and take appropriate actions, such as reverting the transaction or adjusting the logic.

6. Fail with error 'ERC20: transfer amount exceeds allowance'

The `ERC20: transfer amount exceeds allowance` error occurs when an attempt is made to transfer tokens on behalf of another user, but the amount being transferred exceeds the allowance that the token owner has set for the spender.

Cause:
This error is thrown by the `transferFrom` function of the ERC-20 token contract when the amount to be transferred is greater than the allowed limit set by the token owner.

Solution:

  1. Ensure that the token owner has set an adequate allowance for the spender using the `approve` function.
  2. Check the current allowance before attempting the `transferFrom` operation.
  3. If necessary, ask the token owner to increase the allowance by calling the `approve` function with a higher value.

7. TRANSFER_FAILED

This error occurs when the transfer of tokens from one address to another fails. The `_safeTransfer` function ensures the transfer operation succeeds and the returned data, if any, decodes to `true`.


    `function _safeTransfer(address token, address to, uint value) private { (bool 
    success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to,
    value)); require(success && (data.length == 0 || abi.decode(data, (bool))),
    'Pancake: TRANSFER_FAILED'); }`

Cause:

  1. The `token.call` function does not execute successfully (i.e., `success` is `false`).
  2. The call returns data that does not decode to `true`, indicating a failure in the token contract's `transfer` function.

Solution:

  1. Ensure ERC-20 Compliance: Verify that the token contract adheres to the ERC-20 standard, which includes implementing the `transfer` function correctly.
  2. Correct Parameters: Ensure the `to` address is valid and the `value` is within allowable limits, considering the sender's balance and the contract's logic.
  3. Additional Conditions: Check if the token contract requires additional conditions such as pre-approval of the spending amount (`approve` and `allowance` functions).

INSUFFICIENT_LIQUIDITY

8. INSUFFICIENT_OUTPUT_AMOUNT

This error occurs in a decentralized exchange context when the output amount of a token swap is less than the minimum amount specified by the user. This is a safeguard to ensure users do not receive fewer tokens than they expected due to slippage or price changes during the transaction.


    `require(amounts[amounts.length - 1] >= amountOutMin,
    'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');`

Cause:

  1. Market volatility affecting token prices between the time the transaction is initiated and when it is executed.
  2. High slippage settings, which allow for significant deviations in expected outputs.
  3. Insufficient liquidity in the trading pool, causing larger price impacts

Solution:

  1. Ensure ERC-20 Compliance: Verify that the token contract adheres to the ERC-20 standard, which includes implementing the `transfer` function correctly.
  2. Correct Parameters: Ensure the `to` address is valid and the `value` is within allowable limits, considering the sender's balance and the contract's logic.
  3. Additional Conditions: Check if the token contract requires additional conditions such as pre-approval of the spending amount (`approve` and `allowance` functions)./li>

9. INSUFFICIENT_INPUT_AMOUNT

This error occurs when neither of the input amounts for a token swap are greater than zero. It ensures that at least one of the input amounts (`amount0In` or `amount1In`) is positive to proceed with the swap.


    uint amount0In = ...; // Input amount of token0
    uint amount1In = ...; // Input amount of token1
    require(amount0In > 0 || amount1In > 0, 'Pancake: INSUFFICIENT_INPUT_AMOUNT');

Cause:

  1. Incorrect input parameters for the swap function.
  2. Insufficient funds in the user's account.
  3. Mistakes in the logic calculating the input amounts.

Solution:

  1. Validate Input Amounts: Ensure that the input amounts are correctly set before invoking the swap function. This involves proper user input validation and parameter setting.
  2. Check User Balances: Verify that the user has sufficient balance of the tokens intended for the swap. This can be done by calling the `balanceOf` function of the respective token contracts.

10. Fail

Cause:

  1. A transaction cannot be executed because it lacks enough gas to complete all operations.
  2. Incorrect logic or conditions within a smart contract can cause execution to fail (for example, a call to require or assert that fails).
  3. Attempting to execute a token or cryptocurrency transaction when the account balance is insufficient.
  4. In the case of working with ERC-20 and ERC-721 standard tokens, the transaction may fail due to insufficient permissions.
  5. A call to a smart contract may be rolled back due to failure to fulfil conditions within it (e.g. using the revert function).

Solution:

  1. Increase the gas limit when sending the transaction.
  2. Check the conditions and logic within the smart contract.
  3. Make sure the account has enough funds to complete the transaction.
  4. Call the approve function with sufficient value before calling transferFrom.
  5. Check the conditions that cause the transaction to be rolled back.
  6. Check your balance for commissions

Conclusion

Understanding and resolving these common errors in ERC-20 smart contracts requires a solid grasp of Solidity programming, the ERC-20 standard, and the inner workings of decentralized exchanges. By carefully reviewing the causes and implementing the suggested solutions, developers can create more robust and reliable smart contracts, ensuring a seamless experience for users in the decentralized ecosystem.

All posts

Connect to a wallet

Metamask