Assessment reports>Points Farm>Medium findings>Tokens from previous migrations may be lost
Category: Coding Mistakes

Tokens from previous migrations may be lost

Medium Severity
Medium Impact
Medium Likelihood

Description

Inside the migrate function, after verifying the signature, the _migrate function is called to update the user’s balance and grant the migrator contract approval to transfer the user’s tokens.

function _migrate(
     address _user,
     address _destination,
     address _migratorContract,
     address[] calldata _tokens,
     uint256[] memory _amounts
 ) internal {
     uint256 length = _tokens.length;
     //effects for-loop (state changes)
     for (uint256 i; i < length; ++i) {
         //if the balance has been already set to zero, then _tokens[i] is a duplicate of a previous token in the array
         if (balance[_tokens[i]][_user] == 0) revert DuplicateToken();

         balance[_tokens[i]][_user] = 0;
     }

     emit Migrate(
         ++eventId,
         _user,
         _tokens,
         _destination,
         _migratorContract,
         _amounts
     );

     //interactions for-loop (external calls)
     for (uint256 i; i < length; ++i) {
         IERC20(_tokens[i]).approve(_migratorContract, _amounts[i]);
     }
 //...

However, the approve function may decrease the allowance of the user, and if the previous allowance was not transferred, it may be lost since the user balance is set to zero between each migration.

The vulnerability comes from ERC-20's _approve function, which sets the spender’s allowance without checking if the previous allowance was transferred or not.

Impact

Depending on the implementation of the migrator contract, the user may lose funds.

For example, if the user first migrates two tokens, then the contract will approve for two tokens. If the migrator does not transfer the tokens directly, and meanwhile the user wants to migrate one more token, then the allowance will be decreased to one by the approve function and the migrator contract will only be able to transfer a single token — not three, as intended.

Recommendations

The contract should use the function safeDecreaseAllowance instead of approve as defined in OpenZeppelin's SafeERC20 implementation.

Remediation

Level will disable the migrate functionality and ask users to withdraw funds and convert them to lvlUSD tokens by other means.

Zellic © 2025Back to top ↑