Platform: Code4rena
Start Date: 18/10/2023
Pot Size: $36,500 USDC
Total HM: 17
Participants: 77
Period: 7 days
Judge: MiloTruck
Total Solo HM: 5
Id: 297
League: ETH
Rank: 33/77
Findings: 3
Award: $130.38
🌟 Selected for report: 0
🚀 Solo Findings: 0
21.9995 USDC - $22.00
Calling allowSAFE()
directly with a proxy using execute will result in no changes in ODSafeManager, because delegatecall does not alter the context of the target contract.
[!IMPORTANT] Dev comment: You don't need a basic action to call allowSafe, you should be able to call it directly with a proxy using execute
Dev is assuming that you can call allowSAFE()
directly with a proxy using execute, but that can't happend due to the fact that delegatecall don't change the context of the target contract and thus nothing will change in ODSafeManager and users will not be able to call allowSAFE()
. Same thing for the allowHandler()
function.
[!NOTE] Every function with
safeAllowed()
orhandlerAllowed()
modifier will be affected by this vulnerability.
For more information please visit: https://docs.soliditylang.org/en/v0.4.21/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries
Manual review
We recommend adding a basic action to allow allowSAFE() in the BasicActions contract.
call/delegatecall
#0 - c4-pre-sort
2023-10-26T05:15:09Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-10-26T05:15:36Z
raymondfam marked the issue as duplicate of #76
#2 - c4-pre-sort
2023-10-26T19:04:38Z
raymondfam marked the issue as duplicate of #380
#3 - c4-judge
2023-11-02T18:15:12Z
MiloTruck marked the issue as not a duplicate
#4 - c4-judge
2023-11-02T18:15:21Z
MiloTruck marked the issue as duplicate of #294
#5 - c4-judge
2023-11-08T00:26:46Z
MiloTruck marked the issue as satisfactory
54.1911 USDC - $54.19
https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/gov/ODGovernor.sol#L41
Voting delay doesn't work properly on Arbitrum because it relies on the block.number which doesn't provide users enough time to obtain or delegate voting power before a proposal vote ends.
In ODGovernor
, this function measures the delay between proposal creation and the start of voting:
function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) { return super.votingDelay(); }
And this function represents the delay between the vote start and vote end:
function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) { return super.votingPeriod(); }
Both this function enforces a block delay. This structure is problematic for use on Arbitrum. According to Arbitrum Docs block.number
returns the most recently synced L1 block.number
. Once per minute the block.number
in the Sequencer is synced to the actual L1 block.number
(This may introduce potential vulnerabilities in the governance system):
[!IMPORTANT]
As a general rule, any timing assumptions a contract makes about block numbers and timestamps should be considered generally reliable in the longer term (i.e., on the order of at least several hours) but unreliable in the shorter term (minutes).
Wall Clock time | 12:00 am | 12:00:15 am | 12:00:15 am | 12:00:45 am | 12:01 am | 12:01:15 am |
---|---|---|---|---|---|---|
L1 block.number | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 |
L2 block.number | 1000 | 1000 | 1000 | 1000 | 1004 | 1004 |
Arbitrum Block number (from RPCs) | 370000 | 370005 | 370006 | 370008 | 370012 | 370015 |
And the fact that Arbitrum block time is 2-second. Thus voters will not have enough time to vote, or delegate it, before the voting of a proposal ends.
This is the current config:
constructor( address _token, TimelockController _timelock ) Governor('ODGovernor') // @audit GovernorSettings(1, 15, 0) GovernorVotes(IVotes(_token)) GovernorVotesQuorumFraction(3) GovernorTimelockControl(_timelock) {}
initialVotingDelay == 2 seconds
initialVotingPeriod == 30 seconds
initialProposalThreshold == 0 seconds
Which doesn't provide users enough time to obtain or delegate voting power before a proposal vote ends.
Manual review
Replace block.number with block.timestamp and increase the above variables to provide voters with sufficient time to take action.
Timing
#0 - c4-pre-sort
2023-10-26T05:29:05Z
raymondfam marked the issue as low quality report
#1 - c4-pre-sort
2023-10-26T05:29:19Z
raymondfam marked the issue as duplicate of #73
#2 - c4-judge
2023-11-02T08:47:11Z
MiloTruck marked the issue as satisfactory
54.1911 USDC - $54.19
https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/CamelotRelayer.sol#L20 https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/UniV3Relayer.sol#L18
Protocol will not work on arbitrum due to hardcoded _UNI_V3_FACTORY
and _CAMELOT_FACTORY
contract addresses
_CAMELOT_FACTORY
in the CamelotRelayer
is hardcoded as:
address constant GOERLI_CAMELOT_V3_FACTORY = 0x5Cd40c7E21A15E7FC2503Fffd77cF70c60628F6C; // AlgebraFactory
But this address is the AlgebraFactory address in goerli arbitrium, but it is not on arbitrum:
https://arbiscan.io/address/0x5Cd40c7E21A15E7FC2503Fffd77cF70c60628F6C
Note: Same for _UNI_V3_FACTORY
https://arbiscan.io/address/0x4893376342d5D7b3e31d4184c08b265e5aB2A3f6
Manual review
Use valid addresses for _UNI_V3_FACTORY
and _CAMELOT_FACTORY
Other
#0 - c4-pre-sort
2023-10-26T05:52:16Z
raymondfam marked the issue as low quality report
#1 - c4-pre-sort
2023-10-26T05:52:26Z
raymondfam marked the issue as duplicate of #119
#2 - c4-judge
2023-11-02T08:46:44Z
MiloTruck marked the issue as satisfactory