Platform: Code4rena
Start Date: 25/08/2022
Pot Size: $75,000 USDC
Total HM: 35
Participants: 147
Period: 7 days
Judge: 0xean
Total Solo HM: 15
Id: 156
League: ETH
Rank: 20/147
Findings: 3
Award: $1,193.84
π Selected for report: 2
π Solo Findings: 0
π Selected for report: hansfriese
Also found by: V_B, berndartmueller, csanuragjain, m9800, zzzitron
625.0708 DAI - $625.07
https://github.com/code-423n4/2022-08-olympus/blob/2a0b515012b4a40076f6eac487f7816aafb8724a/src/policies/Governance.sol#L216-L221 https://github.com/code-423n4/2022-08-olympus/blob/2a0b515012b4a40076f6eac487f7816aafb8724a/src/policies/Governance.sol#L302-L304
Currently, if users vote for the active proposal, the VOTES
are transferred to the contract so that users can't vote or endorse other proposals while the voted proposal is active.
And the active proposal can be replaced only when the proposal is executed successfully or another proposal is activated after GRACE_PERIOD
.
But activateProposal()
requires at least 20% endorsements here, so it might be impossible to activate a new proposal forever if the current active proposal involves more than 80% of total votes.
The below scenario would be possible.
Proposal 1
was submitted and activated successfully.Yes = 47%
, No = 34%
47% - 34% = 13% < 33%
.Proposal 1
is active.Proposal 1
from an active proposal and there won't be other active proposal forever.Solidity Visual Developer of VSCode
I think we should add one more constant like EXECUTION_EXPIRE = 2 weeks
so that voters can reclaim their votes after this period even if the proposal is active.
I am not sure we can use the current GRACE_PERIOD
for that purpose.
So reclaimVotes()
should be modified like below.
function reclaimVotes(uint256 proposalId_) external { uint256 userVotes = userVotesForProposal[proposalId_][msg.sender]; if (userVotes == 0) { revert CannotReclaimZeroVotes(); } if (proposalId_ == activeProposal.proposalId) { if (block.timestamp < activeProposal.activationTimestamp + EXECUTION_EXPIRE) //+++++++++++++++++++++++++++++++++ { revert CannotReclaimTokensForActiveVote(); } } if (tokenClaimsForProposal[proposalId_][msg.sender] == true) { revert VotingTokensAlreadyReclaimed(); } tokenClaimsForProposal[proposalId_][msg.sender] = true; VOTES.transferFrom(address(this), msg.sender, userVotes); }
#0 - csanuragjain
2022-09-02T06:21:36Z
Seems like duplicate of https://github.com/code-423n4/2022-08-olympus-findings/issues/362
#1 - fullyallocated
2022-09-04T02:27:35Z
This is probably the best response for this issue.
#2 - 0xean
2022-09-19T14:58:47Z
using this as the primary issue.
π Selected for report: hansfriese
514.4616 DAI - $514.46
https://github.com/code-423n4/2022-08-olympus/blob/2a0b515012b4a40076f6eac487f7816aafb8724a/src/modules/RANGE.sol#L80 https://github.com/code-423n4/2022-08-olympus/blob/2a0b515012b4a40076f6eac487f7816aafb8724a/src/modules/RANGE.sol#L244-L250 https://github.com/code-423n4/2022-08-olympus/blob/2a0b515012b4a40076f6eac487f7816aafb8724a/src/modules/RANGE.sol#L264 https://github.com/code-423n4/2022-08-olympus/blob/2a0b515012b4a40076f6eac487f7816aafb8724a/src/policies/Operator.sol#L134 https://github.com/code-423n4/2022-08-olympus/blob/2a0b515012b4a40076f6eac487f7816aafb8724a/src/policies/Operator.sol#L518
Inconsistant parameter requirements between constructor
and Set() functions
in RANGE.sol
and Operator.sol
.
The contracts might work unexpectedly when the params are set improperly using constructor()
.
RANGE.sol
, setSpreads() and setThresholdFactor() has some requirements but constructor() doesn't check at all.File: 2022-08-olympus\src\modules\RANGE.sol 242: function setSpreads(uint256 cushionSpread_, uint256 wallSpread_) external permissioned { 243: // Confirm spreads are within allowed values 244: if ( 245: wallSpread_ > 10000 || 246: wallSpread_ < 100 || 247: cushionSpread_ > 10000 || 248: cushionSpread_ < 100 || 249: cushionSpread_ > wallSpread_ 250: ) revert RANGE_InvalidParams(); 251: 252: // Set spreads 253: _range.wall.spread = wallSpread_; 254: _range.cushion.spread = cushionSpread_; 255: 256: emit SpreadsChanged(wallSpread_, cushionSpread_); 257: }
File: 2022-08-olympus\src\modules\RANGE.sol 263: function setThresholdFactor(uint256 thresholdFactor_) external permissioned { 264: if (thresholdFactor_ > 10000 || thresholdFactor_ < 100) revert RANGE_InvalidParams(); 265: thresholdFactor = thresholdFactor_; 266: 267: emit ThresholdFactorChanged(thresholdFactor_); 268: } 269:
Operator.sol
, setCushionFactor() checks the requirement but constructor() doesn't check it.File: 2022-08-olympus\src\policies\Operator.sol 516: function setCushionFactor(uint32 cushionFactor_) external onlyRole("operator_policy") { 517: /// Confirm factor is within allowed values 518: if (cushionFactor_ > 10000 || cushionFactor_ < 100) revert Operator_InvalidParams(); 519: 520: /// Set factor 521: _config.cushionFactor = cushionFactor_; 522: 523: emit CushionFactorChanged(cushionFactor_); 524: } 525:
Solidity Visual Developer of VSCode
Recommend adding same validation for the parameters between constructor()
and Set()
functions.
#0 - Oighty
2022-09-07T00:46:33Z
Agree that the constructor should validate these parameters, but it is only an issue if configured improperly.
#1 - 0xean
2022-09-19T14:17:59Z
while I am typically weary of marking input validations as medium severity, I do think in this case its warranted as it directly leads to malfunctions at the protocol level and it seems that the sponsors thought it important enough to add the checks elsewhere. Hard call, but will award it at medium sev.
π Selected for report: zzzitron
Also found by: 0x040, 0x1f8b, 0x52, 0x85102, 0xDjango, 0xNazgul, 0xNineDec, 0xSky, 0xSmartContract, 0xkatana, 8olidity, Aymen0909, Bahurum, BipinSah, Bnke0x0, CRYP70, CertoraInc, Ch_301, Chandr, Chom, CodingNameKiki, Deivitto, DimSon, Diraco, ElKu, EthLedger, Funen, GalloDaSballo, Guardian, IllIllI, JansenC, Jeiwan, Lambda, LeoS, Margaret, MasterCookie, PPrieditis, PaludoX0, Picodes, PwnPatrol, RaymondFam, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, StevenL, The_GUILD, TomJ, Tomo, Trust, Waze, __141345__, ajtra, ak1, apostle0x01, aviggiano, bin2chen, bobirichman, brgltd, c3phas, cRat1st0s, carlitox477, cccz, ch13fd357r0y3r, cloudjunky, cryptphi, csanuragjain, d3e4, datapunk, delfin454000, devtooligan, dipp, djxploit, durianSausage, eierina, enckrish, erictee, fatherOfBlocks, gogo, grGred, hansfriese, hyh, ignacio, indijanc, itsmeSTYJ, ladboy233, lukris02, martin, medikko, mics, natzuu, ne0n, nxrblsrpr, okkothejawa, oyc_109, p_crypt0, pfapostol, prasantgupta52, rajatbeladiya, rbserver, reassor, ret2basic, robee, rokinot, rvierdiiev, shenwilly, sikorico, sorrynotsorry, tnevler, tonisives, w0Lfrum, yixxas
54.3128 DAI - $54.31
Change a-z only
=> "a-z", "_" only