Platform: Code4rena
Start Date: 24/07/2023
Pot Size: $100,000 USDC
Total HM: 18
Participants: 73
Period: 7 days
Judge: alcueca
Total Solo HM: 8
Id: 267
League: ETH
Rank: 28/73
Findings: 3
Award: $239.81
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: immeas
Also found by: 0xComfyCat, Vagner, ast3ros, kutugu, markus_ether, volodya
151.5613 USDC - $151.56
The function executeProposal
is used with the wormhole bridge to execute proposals from different chains, but it doesn't check if the VAA processed is meant to be sent to that address.
As you can see it is specified in both queueProposal
and executeProposal
that is important that the VAA is processed only once and critically, intended for that contract
https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Governance/TemporalGovernor.sol#L226
https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Governance/TemporalGovernor.sol#L235
For queueProposal
case this is correctly checked in this require statement
https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Governance/TemporalGovernor.sol#L322
but there is not checks in the executeProposal
proposals, which could lead to wrong assumptions, doing external calls with different values to random addresses in the case where the intended address is not TemporalGovernor.sol
. This is especially dangerous fastTrackProposalExecution
where checks like queueTime
would pass, and the calls will be done immediately. This could also lead to loss of funds is value
is meant to be sent with those calls.
Manual review
Do the same checks in _executeProposal
like in _queueProposal
since you specify in the comments that it is critically to check this.
Governance
#0 - c4-pre-sort
2023-08-03T13:24:12Z
0xSorryNotSorry marked the issue as duplicate of #308
#1 - c4-judge
2023-08-12T20:27:28Z
alcueca marked the issue as satisfactory
#2 - c4-judge
2023-08-12T20:27:32Z
alcueca marked the issue as partial-50
#3 - c4-judge
2023-08-21T21:38:33Z
alcueca changed the severity to 2 (Med Risk)
43.3709 USDC - $43.37
The contract TemporalGovernor.sol
is used to queue and execute proposals on other chains with data and values, but that is not possible since the contract can't receive native tokens.
As you can see the function executeProposal
and fastTrackProposalExecution
are not payable
https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Governance/TemporalGovernor.sol#L237
https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Governance/TemporalGovernor.sol#L266
and the contract doesn't have any receive function, nor the contracts that it inherits, so any time the _executeProposal
would be called with any of the values
array value greater than 0, the transaction would revert because there are no native funds in the contract to be transferred.
Manual review
Implement a receive
function or set any function in the contract payable
to be able to receive native tokens.
ETH-Transfer
#0 - c4-pre-sort
2023-08-03T13:21:17Z
0xSorryNotSorry marked the issue as duplicate of #268
#1 - c4-judge
2023-08-12T20:36:58Z
alcueca marked the issue as satisfactory
#2 - c4-judge
2023-08-12T20:37:01Z
alcueca marked the issue as partial-50
🌟 Selected for report: immeas
Also found by: 0x70C9, 0xAnah, 0xArcturus, 0xComfyCat, 0xWaitress, 0xackermann, 0xkazim, 2997ms, 33audits, Arz, Aymen0909, ChrisTina, JP_Courses, John_Femi, Jorgect, Kaysoft, LosPollosHermanos, MohammedRizwan, Nyx, Rolezn, Sathish9098, Stormreckson, T1MOH, Tendency, Topmark, Udsen, Vagner, albertwh1te, ast3ros, banpaleo5, berlin-101, catellatech, cats, codetilda, cryptonue, eeshenggoh, fatherOfBlocks, hals, jamshed, jaraxxus, josephdara, kankodu, kodyvim, kutugu, lanrebayode77, mert_eren, nadin, naman1778, niki, petrichor, ravikiranweb3, said, solsaver, souilos, twcctop, wahedtalash77
44.8793 USDC - $44.88
The way the rewards are distributed right now, in the MultiRewardDistributor.sol
, can make the whole distribute process unusable because of out-of-gas errors.
The way the whole claiming rewards process, does multiple interactions with multiple contracts and updates multiple storage values in multiple loops, which could lead easily to out-of-gas errors, but let's see the whole claiming process.
Comptroller.sol
contract where a user can claim rewards for all/multiple MTokens, or just one if the array provided contains one, we will take the only one example since that will cost the lowest amount of gas.claimReward
function will be called by an user with only his address and one MToken, taking both rewards for borrowers
and suppliers
rewardDistributor
which is the MultiRewardDistributor.sol
which already cost more gas then calling the functions internally in the MultiRewardDistributor.sol
updateMarketSupplyIndex
is called https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Comptroller.sol#L1039 which will call updateMarketSupplyIndexInternal
in MultiRewardDistributor.sol
, function which loops over some storage variables, and also updates some of those storage variables as can be seen here https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/MultiRewardDistributor/MultiRewardDistributor.sol#L1009-L1024, this means that every SLOAD on a slot that wasn't accessed yet, which will be the case here, will be around 2100 gas, and every SLOAD done in this function that wasn't access yet would cost around 5000, since the values would be updated from non-zero to non-zero value, which happens 2 times in every loop https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/MultiRewardDistributor/MultiRewardDistributor.sol#L1022-L1024disburseSupplierRewards
is then called on the MultiRewardDistributor.sol
, another external call, which calls disburseSupplierRewardsInternal
, function which again loops trough multiple storage values and updates some https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/MultiRewardDistributor/MultiRewardDistributor.sol#L1053-L1068, this time though the SLOAD for accessed slots would cost just 100 gas, only the new slots accessed would cost 2100, but the SSTORE in this function would cost 22100 for the first time an user call this function for that specific marketConfig
, since it updates the value from zero to non-zero on a slot that wasn't accessed yet, which happens 2 times, for every loop, as an example for 3 loops it would cost around 132,600 just to update those 2 variables.marketConfig
which again can cost a lot of gas, depending on what logic there is on the specific token contract (if it checks for blacklist for exemple)borrowers
part by calling updateMarketBorrowIndex
and disburseBorrowerRewards
which does exactly the same things as I specified above, but on new slots, which again costs a lot of gas.
All of these calculations can very easily get to too much gas consumed by this claiming process, which will make the claims impossible, especially because the whole marketConfigs
can't be removed, as it is stated in the NatSpec https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/MultiRewardDistributor/MultiRewardDistributor.sol#L35-L36 which means that every user would have to loop trough every config ever added with _addEmissionConfig
doing the whole process that I talked above. Keep in mind that I talked only for claiming rewards, for only one MToken on only one user, for more than that it will get way more costly which will mostly fail for sure.Manual review
Consider splitting the functionality a bit, the claimReward
function on Comptroller.sol
does too many things at once, also try to work more with memory values by coping the storage values into memory, and then loop trough them, as it cost way less gas, and only update the storage values at the end
Other
#0 - c4-pre-sort
2023-08-03T13:48:41Z
0xSorryNotSorry marked the issue as duplicate of #326
#1 - c4-judge
2023-08-12T20:15:12Z
alcueca changed the severity to QA (Quality Assurance)