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: 34/125
Findings: 2
Award: $81.34
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: SpicyMeatball
Also found by: 0xComfyCat, GREY-HAWK-REACH, Yanchuan, cducrest, immeas, kaden, mert_eren, nonseodion, pep7siup, popular00, ppetrov
71.5198 USDC - $71.52
For a user to receive rewards for supplying cNote in a lending market (LM), he only needs to have supplied the cNote at the end of an epoch. Users staking for the whole duration of an epoch get 0 benefits, compared to users who supply only at the end of the epoch.
Therefore evRWA provides no incentive for users to supply cNote long-term in a specific LM.
Since there is no incentive to stick to one LM, this significantly reduces the incentive to lock cNote for evRWA - there is no need to vote for an LM because the user can choose the LM with the highest weight and redeem the rewards for it with 0 commitment.
This will create an unhealthy dynamic of reward-hunting without long-term commitment to the protocol.
Even if a LM provides good incentives for the user to keep tokens supplied, it is a reasonable assumption to make that protocols with even better incentives will exist.
I believe this to be a high issue because it can be detrimental to the success of the veRWA system. In order to prevent the issue from manifesting, the protocol will have to rely on the LMs to over-incentivize or to enforce long minimum deposit durations. No such requirements for the LMs have been described in the audit docs, which leads me to believe that no such requirements have been considered.
function sync_ledger(address _lender, int256 _delta) external { address lendingMarket = msg.sender; require(lendingMarketWhitelist[lendingMarket], "Market not whitelisted"); _checkpoint_lender(lendingMarket, _lender, type(uint256).max); uint256 currEpoch = (block.timestamp / WEEK) * WEEK; int256 updatedLenderBalance = int256(lendingMarketBalances[lendingMarket][_lender][currEpoch]) + _delta; require(updatedLenderBalance >= 0, "Lender balance underflow"); // Sanity check performed here, but the market should ensure that this never happens lendingMarketBalances[lendingMarket][_lender][currEpoch] = uint256(updatedLenderBalance); _checkpoint_market(lendingMarket, type(uint256).max); int256 updatedMarketBalance = int256(lendingMarketTotalBalance[lendingMarket][currEpoch]) + _delta; require(updatedMarketBalance >= 0, "Market balance underflow"); // Sanity check performed here, but the market should ensure that this never happens lendingMarketTotalBalance[lendingMarket][currEpoch] = uint256(updatedMarketBalance); }
Manual review
To encourage supplying tokens over the whole duration of an epoch, changes to the reward calculation mechanism can be made. An alternative would be to enforce a rule for minimum LM deposit duration of 1 Epoch in order to be whitelisted. But this might not be viable due to the varying natures of the different lending markets.
Protocol changes could look like:
Instead of using the absolute balance of the user to calculate rewards, the protocol can use a linearly increasing average balance. This can be employed with simple math as in Example_1 or by using the already familiar slope of a line (increasing).
Example_1: epoch = 100 seconds Starting totalSupply = 1000 tokens
Alice average supply is 95/10010 + 5/1001010 = 9.5 + 50.5 = 60 tokens Average total supply = 101095/100 + 20105/100 = 959.5 + 100.5 = 1060 tokens
Alice's share = 60/1060 tokens = 5.66&
Example_2:
epoch = 100 seconds Starting totalSupply = 1000 tokens
At the end of the 100s her total tokens = 1095/100 + 10105/100 = 60 tokens (just like in Example_1)
Context
#0 - c4-pre-sort
2023-08-13T07:29:06Z
141345 marked the issue as duplicate of #71
#1 - c4-judge
2023-08-25T11:00:07Z
alcueca changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-08-25T11:01:29Z
alcueca changed the severity to 3 (High Risk)
#3 - c4-judge
2023-08-25T11:02:40Z
alcueca marked the issue as partial-50
🌟 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
If rewards are accidentally not set for a single epoch, this will cause a revert in all transactions, trying to claim their rewards for period 0 -> type(uint256).max
The provided revert does not indicate for which epoch there is no rewards set and will force the user to either
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
Error
#0 - c4-pre-sort
2023-08-12T16:30:56Z
141345 marked the issue as duplicate of #44
#1 - c4-judge
2023-08-24T21:34:14Z
alcueca changed the severity to QA (Quality Assurance)
#2 - c4-judge
2023-08-24T21:34:20Z
alcueca marked the issue as grade-a