stake.link

stake.link
DeFiHardhatBridge
27,500 USDC
View results
Submission Details
Severity: high
Valid

The `tokenApprovals[_lockId]` is not deleted if the `ERC721` is transferred between multiple chains

Summary

The tokenApprovals[_lockId] is not deleted if the ERC721 is transferred between multiple chains.

Vulnerability Details

The lockId can be transferred from the primary chain to the secondary chain with the help of the function RESDLTokenBridge::transferRESDL, this will transfer the token to the destination chain. Likewise, you can specify the receiver, that is, in transfer between chains the recipient can be another user.

The problem is that when transferring between chains, the tokenApprovals[_lockId] variable is not cleared. Keep in mind that when the lockId is transferred within the same chain tokenApprovals[_lockId] is deleted:

File: SDLPool.sol
455: function _transfer(
456: address _from,
457: address _to,
458: uint256 _lockId
459: ) internal virtual {
460: if (_from != ownerOf(_lockId)) revert TransferFromIncorrectOwner();
461: if (_to == address(0)) revert TransferToZeroAddress();
462: if (_to == ccipController) revert TransferToCCIPController();
463:
464: delete tokenApprovals[_lockId];
465:
466: _updateRewards(_from);
467: _updateRewards(_to);
468:
469: uint256 effectiveBalanceChange = locks[_lockId].amount + locks[_lockId].boostAmount;
470: effectiveBalances[_from] -= effectiveBalanceChange;
471: effectiveBalances[_to] += effectiveBalanceChange;
472:
473: balances[_from] -= 1;
474: balances[_to] += 1;
475: lockOwners[_lockId] = _to;
476:
477: emit Transfer(_from, _to, _lockId);
478: }

Impact

The tokenApprovals[_lockId] will be cleared when the ERC721 is transferred within the same chain however tokenApprovals[_lockId] is NOT cleared when the transfer is made between multiple chains.

Tools used

Manual review

Recommendations

Clear tokenApprovals[_lockId] when transferring ERC721 on multiple chains:

function handleOutgoingRESDL(
address _sender,
uint256 _lockId,
address _sdlReceiver
)
external
onlyCCIPController
onlyLockOwner(_lockId, _sender)
updateRewards(_sender)
updateRewards(ccipController)
returns (Lock memory)
{
Lock memory lock = locks[_lockId];
++ // remove token approvals
delete locks[_lockId].amount;
delete lockOwners[_lockId];
balances[_sender] -= 1;
uint256 totalAmount = lock.amount + lock.boostAmount;
effectiveBalances[_sender] -= totalAmount;
effectiveBalances[ccipController] += totalAmount;
sdlToken.safeTransfer(_sdlReceiver, lock.amount);
emit OutgoingRESDL(_sender, _lockId);
return lock;
}
Updates

Lead Judging Commences

0kage Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

stale-approval

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.