Platform: Code4rena
Start Date: 05/10/2023
Pot Size: $33,050 USDC
Total HM: 1
Participants: 54
Period: 6 days
Judge: hansfriese
Id: 294
League: ETH
Rank: 4/54
Findings: 2
Award: $1,779.62
🌟 Selected for report: 0
🚀 Solo Findings: 0
1774.1935 USDC - $1,774.19
https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L148 https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L159-L161 https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L163-L171
ERC20MultiDelegate
uses transferFrom()
to move the ERC20 tokens in/out of the proxy contracts (see code below).
However, it fails to check the return value of transferFrom()
. It is documented in EIP20 that callers must handle a false
return value and must not assume false
is never returned.
Some tokens such as ZRX and EURS do not revert in failure and instead returns false on failure.
Due to the missing check, the transferFrom()
could fail silently and continue to mint/burn the ERC20MultiDelegate
ERC1155 token. That will cause token holders to incur lossses as they do not receive the ERC20 tokens on withdrawals.
function _reimburse(address source, uint256 amount) internal { // Transfer the remaining source amount or the full source amount // (if no remaining amount) to the delegator address proxyAddressFrom = retrieveProxyContractAddress(token, source); //@audit missing check for return value from transferFrom() token.transferFrom(proxyAddressFrom, msg.sender, amount); }
Note that this finding was disputed in the bot report likely based on the assessment that the ENSToken is using OZ ERC20 that will revert on failure. However, sponsor has clarified that the scope extends beyond ENSToken with the remark "The primary target for the token is to wrap $ENS. But the audit should consider any ERC20-compliant token that implements ERC20Votes as in-scope."
Due to the issue, there will be a mismatch in the mapping of the ERC20MultiDelegate
ERC1155 tokens to the ERC20 tokens.
Token holders/proxy contracts will not receive ERC20 tokens when the outgoing transfer from proxy contract fails. On the other hand, token holders/proxy contracts can incorrectly gain ERC20 tokens when the incoming transfer into proxy contract fails.
Imagine the scenario,
delegateMulti()
to delegate 1000 ENSToken to Bob.transferFrom()
failed silently but Alice still received the ERC20MultiDelegate
ERC1155 tokens even thought the 1000 ENSToken remains in her account.delegateMulti()
to delegate 2000 ENSToken to Bob and transferFrom()
suceeded.delegateMulti()
and withdraw 1000 ENSToken and steal from Charlie.Wrap the transferFrom()
with require()
.
Invalid Validation
#0 - c4-pre-sort
2023-10-12T07:30:22Z
141345 marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-10-12T07:30:28Z
141345 marked the issue as duplicate of #91
#2 - c4-judge
2023-10-23T12:30:55Z
hansfriese changed the severity to 2 (Med Risk)
#3 - c4-judge
2023-10-24T17:11:21Z
hansfriese marked the issue as satisfactory
#4 - c4-judge
2023-10-28T06:23:39Z
hansfriese marked the issue as duplicate of #90
#5 - c4-judge
2023-10-28T08:32:33Z
hansfriese marked the issue as not a duplicate
#6 - c4-judge
2023-10-28T08:32:43Z
hansfriese changed the severity to 3 (High Risk)
#7 - c4-judge
2023-10-28T08:32:56Z
hansfriese marked the issue as duplicate of #91
#8 - c4-judge
2023-10-29T10:13:32Z
hansfriese changed the severity to 2 (Med Risk)
🌟 Selected for report: thekmj
Also found by: 0x3b, 33BYTEZZZ, Bauchibred, Chom, Dravee, J4X, Limbooo, Maroutis, MiloTruck, MrPotatoMagic, SBSecurity, Sathish9098, Tadev, ZanyBonzy, adam-idarrha, adriro, btk, hyh, lukejohn, nmirchev8, peakbolt, radev_sw, rvierdiiev
5.4311 USDC - $5.43
https://github.com/code-423n4/2023-10-ens/blob/main/contracts/ERC20MultiDelegate.sol#L17
During deployment of ERC20ProxyDelegator
, it calls _token.approve()
to grant spending allowance for ERC20MultiDelegate
contract (see below).
The issue is the missing check for return value of approve()
, which is mandated by EIP20 to ensure that false return value are handled.
If the approve()
fails without revert and only returns false, the ERC20ProxyDelegator
will fail to grant allowance for ERC20MultiDelegate
. That will be disastrous as ERC20MultiDelegate
will not be able to transfer ERC20 tokens out of the proxy contracts, causing the ERC20 tokens to be permanently lock in it as there are no mechanism to reapprove the allowance.
contract ERC20ProxyDelegator { constructor(ERC20Votes _token, address _delegate) { _token.approve(msg.sender, type(uint256).max); _token.delegate(_delegate); } }
Note that this finding was disputed in the bot report likely based on the assessment that the ENSToken is using OZ ERC20 that will revert on failure. However, sponsor has clarified that the scope extends beyond ENSToken with the remark "The primary target for the token is to wrap $ENS. But the audit should consider any ERC20-compliant token that implements ERC20Votes as in-scope."
The issue can cause ERC20 tokens in the proxy contracts to be permanently locked.
delegateMulti()
to delegate 1000 ENS Tokens to Bob.ERC20ProxyDelegator
for Bob is deployed for the first time.approve()
fails sliently but Alice's 1000 ENSTokens is still transferred into the proxy contract.ERC20MultiDelegate
is not granted allowance due to the failed approve().Wrap approve()
with require()
.
Invalid Validation
#0 - c4-pre-sort
2023-10-12T15:23:15Z
141345 marked the issue as duplicate of #30
#1 - c4-pre-sort
2023-10-13T01:24:35Z
141345 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-24T15:29:42Z
hansfriese changed the severity to QA (Quality Assurance)
#3 - c4-judge
2023-10-24T16:37:56Z
hansfriese marked the issue as grade-b