Platform: Code4rena
Start Date: 07/08/2023
Pot Size: $36,500 USDC
Total HM: 11
Participants: 125
Period: 3 days
Judge: alcueca
Total Solo HM: 4
Id: 274
League: ETH
Rank: 12/125
Findings: 2
Award: $314.08
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: RED-LOTUS-REACH
Also found by: 0x3b, 0x4non, 0xCiphky, 0xDING99YA, 0xDetermination, 0xE1, 0xG0P1, 0xStalin, 0xWaitress, 0xbrett8571, 0xhacksmithh, 0xkazim, 0xmuxyz, 0xweb3boy, 14si2o_Flint, AlexCzm, Alhakista, Bube, Bughunter101, Deekshith99, Eeyore, Giorgio, HChang26, InAllHonesty, JP_Courses, KmanOfficial, MatricksDeCoder, Mike_Bello90, MrPotatoMagic, Naubit, QiuhaoLi, RHaO-sec, Raihan, Rolezn, SUPERMAN_I4G, Shubham, Silverskrrrt, Strausses, T1MOH, Topmark, Tripathi, Watermelon, _eperezok, aakansha, auditsea, audityourcontracts, ayden, carlos__alegre, castle_chain, cducrest, ch0bu, d23e, deadrxsezzz, deth, devival, erebus, fatherOfBlocks, halden, hassan-truscova, hpsb, hunter_w3b, imkapadia, immeas, jat, kaden, kaveyjoe, klau5, koxuan, kutugu, ladboy233, lanrebayode77, leasowillow, lsaudit, markus_ether, matrix_0wl, merlin, nemveer, ni8mare, nonseodion, oakcobalt, owadez, p_crypt0, pipidu83, piyushshukla, popular00, ppetrov, rjs, sandy, sl1, supervrijdag, tay054, thekmj, wahedtalash77, windhustler, zhaojie
9.8204 USDC - $9.82
Description Events are used by users and other systems to reliably detect protocol state for integration, market information and exploit detection purposes.
There are some critical operations that do not emit events:
Recommendation Implement the listed events to improve contract transparency.
Description While much of the code is based on well-established protocols, the various modifications and specializations would benefit from clear documentation about the broader context, types of users, interactions with and between contracts, arithmetic properties and access controls. The lack of documentation makes the protocol difficult to review.
Recommendation Fully document the solution
GaugeController
Description
This issue was identified in the original Curve Finance audit, finding ID TOB-CURVE-DAO-017. It remains unresolved in the mkt.market
implementation.
GaugeController
voting offers no incentive to vote early, so late-voting users have a benefit over early voters.
Given that votes are public, earlier voters reveal information to other voters. An unethical voter could wait until the last moment to vote, and calculate the minimal effective vote. Effectively, earlier voters have to use more power for the same effect as last-minute voters.
Recommendation Consider using a decreasing vote weight to compensate early voters for revealing their intentions, or use a blind voting protocol.
user
and gauge
in testsScope: While the tests are out of scope for the audit, the test still effectively form part of the documentation for the project.
The tests setup 2 test user
and gauge
addresses each:
/home/rjs/Desktop/code-423n4/2023-08-verwa/src/test/GaugeController.t.sol:27 27: users = utils.createUsers(5); 28: (gov, user1, user2, gauge1, gauge2) = (users[0], users[1], users[2], users[3], users[4]);
But the test code mixes the usage of addresses, which makes it difficult to understand the intention behind the test.
For example, in the below test, user1
's address is the gauge:
src/test/GaugeController.t.sol:34 34: function testAddGauge() public { 35: assertTrue(!gc.isValidGauge(user1)); 36: vm.startPrank(gov); 37: gc.add_gauge(user1); 38: vm.stopPrank(); 39: assertTrue(gc.isValidGauge(user1)); 40: }
Whereas in this test, user1
is the user:
src/test/GaugeController.t.sol:159 159: function testVoteGaugeWeight50Pcnt() public { 160: // vote_for_gauge_weights valid vote 50% 161: // Should vote for gauge and change weights accordingly 162: vm.startPrank(gov); 163: gc.add_gauge(gauge1); 164: gc.add_gauge(gauge2); 165: gc.change_gauge_weight(gauge1, 50); 166: gc.change_gauge_weight(gauge2, 50); 167: vm.stopPrank(); 168: 169: vm.startPrank(user1); 170: ve.createLock{value: 1 ether}(1 ether); 171: gc.vote_for_gauge_weights(gauge1, 5000); // vote 50% for gauge1 172: gc.vote_for_gauge_weights(gauge2, 5000); // vote 50% for gauge2 173: 174: assertEq((gc.get_total_weight() * 5000) / 10000, gc.get_gauge_weight(gauge1)); 175: }
#0 - 141345
2023-08-13T08:04:40Z
#1 - c4-judge
2023-08-22T13:49:17Z
alcueca marked the issue as grade-a
🌟 Selected for report: catellatech
Also found by: 0x73696d616f, 0xSmartContract, 0xbrett8571, MrPotatoMagic, RED-LOTUS-REACH, rjs, thekmj
veRWA is a voting escrow implementation for CANTO Real World Assets. The implementation under audit covers the core GaugeController
, VotingEscrow
and LendingLedger
contracts. The first two contracts are heavily based on Curve Finance's original Vyper implementation, while the LendingLedger
is a
an original piece of code.
This was a 3 day contest:
readme.md
and drafted an audit strategyGaugeController.sol
, VotingEscrow.sol
and LendingLedger.sol
GaugeController.sol
to Curve's Vyper implementation, line-by-lineVotingEscrow.sol
to FIAT DAO implementation using file diffAdditional Context
section of the readme.md
fileThe readme.md
did not link to a project documentation page. I tried to track down veCANTO
and veRWA
but was unable to turn up further information. RWA
appears to be a generic term, and CANTO
documentation doesn't appear to reference the project either . The mkt.market
site didn't appear to have project information.
The code documentation did have very well-documented lineage in 2 out of 3 cases, and I was able to reference sufficient relevant documentation to audit those contracts.
Codebase had good test coverage, and was relatively well laid out.
The mechanism here is based heavily on the Curve Finance protocol:
GaugeController
As discussed in my QA report, voting early reveals information to other voters. This effectively reduces the power of a user's vote. To compensate for this, consider implementing:
LendingLedger
While the readme
states that governance operations are always assumed to be correct, human error should always be considered in protocol design.
The recent CRV hack exposed a problem where one of the founders had used $280 million CRV as loan collateral for a $100 Real World Asset (a house), and the devaluing of the CRV used as collateral put the loan at risk of liquidation.
This would have dumped millions of CRV onto the market, and caused the price of CRV to collapse further. This would have caused liquidity providers to withdraw from Curve.
Fortunately this has not yet happened, but demonstrates the problems of large disbursements of liquidity tokens to founders in these styles of protocols.
22 hours
#0 - c4-judge
2023-08-22T06:54:42Z
alcueca marked the issue as grade-a