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: 35/54
Findings: 1
Award: $10.69
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: polarzero
Also found by: 0x3b, 0xSmartContract, 0xnev, ABA, Bulletprime, J4X, Limbooo, MrPotatoMagic, SBSecurity, Sathish9098, asui, d3e4, hyh, ihtishamsudo, inzinko, marchev, pfapostol, radev_sw, rahul, ro1sharkm
10.6913 USDC - $10.69
The ERC20MultiDelegate
enables token/vote transfers to targets or facilitates reimbursements, where different source/target combinations are permissible, provided the total amounts match up. The contract deploys a proxy delegate for each of the targets, that receives tokens, then grants max allowance to the ERC20MultiDelegate contract before delegating votes to the specified target address. For tracking ownership, it inherits from ERC1155, where tokenId
in the function balanceOf(sender, tokenId)
, is the address of the target converted to a uint256.
The flow chart in this post presents a very good summary of protocol flow and mechanism. The following table summarizes the potential use cases of the protocol, assuming the following checks are met:
sourcesLength
and/or targetsLength
matches this check where delegator should provide at least one source or one target delegateamountsLength
matches this check, that is the number of amounts must be equal to the greater of number of source/target delegate. This prevents unintended delegation/transfer/burning/minting of tokens._burnBatch()
: This function call when sourcesLength > 0
is esentially the "access control" here. The delegator must own the ERC1155 ownership token represented by source address (represented by a uint256), to be allowed to perform delegation from source delegate to target delegate.Note that ERC1155 tokens are transferrable and owner of this tokens can approve other users to spend this tokens via ERC1155.setApprovalForAll()
. This means delegation/reimbursement/Transfers can be performed from other addresses.
Scenario | Actions | Use Case |
---|---|---|
sourcesLength = 0, targetsLength > 0 | createProxyDelegatorAndTransfer() | Transfer ERC20Votes tokens from delegator himself to the target delegate proxy (deploy a new proxy if not already deployed) |
sourcesLength > 0, targetsLength = 0 | _reimburse() | Reimburse ERC20Votes tokens from source delegate proxy contract back to delegator himself |
sourcesLength > 0, targetsLength > 0, sourcesLength == targetsLength | _processDelegation() | Transfer ERC20Votes tokens from source delegate to target delegate |
sourcesLength > 0, targetLengths > 0, sourcesLength > targetLength | _processDelegation() , _reimburse() | Transfer ERC20Votes tokens from source delegate to target delegate, Perform reimbursement to delegator for last source delegate |
sourcesLength > 0, targetLengths > 0, sourcesLength < targetLength | _processDelegation() , createProxyDelegatorAndTransfer() | Transfer ERC20Votes tokens from source delegate to target delegate, Perform transfer of tokens from delegator himself to last target delegate |
To further improve the usability of the contract (possibly across multiple EVM compatible chains), a unique chainId could be included when deploying a new ERC20ProxyDelegator
contract.
As mentioned in one of my submissions, the contract does not allow delegating from a single source delegate to multiple different targets and vice versa, causing unexpected results.
The only centralization risk involves allowing the owner to change the ERC1155 URI at any point of time, which describes the meta data and information about each token present in the contract.
36 hours
#0 - c4-pre-sort
2023-10-14T08:44:46Z
141345 marked the issue as sufficient quality report
#1 - c4-judge
2023-10-24T16:48:16Z
hansfriese marked the issue as grade-b