Tokens from previous migrations may be lost
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.