Platform: Code4rena
Start Date: 08/03/2023
Pot Size: $60,500 USDC
Total HM: 2
Participants: 123
Period: 7 days
Judge: hansfriese
Id: 220
League: ETH
Rank: 67/123
Findings: 2
Award: $48.97
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xSmartContract
Also found by: 0x1f8b, 0x6980, 0xAgro, 0xSolus, 0xhacksmithh, 0xkazim, ABA, BPZ, BowTiedOriole, ChainReview, DadeKuma, DeFiHackLabs, Deathstore, DevABDee, Diana, Dravee, Dug, Englave, Go-Langer, Haipls, IceBear, Inspex, Jeiwan, Kek, Kresh, Madalad, MatricksDeCoder, MyFDsYours, RaymondFam, Rolezn, SAAJ, Sathish9098, Taloner, Udsen, Viktor_Cortess, atharvasama, ayden, brgltd, btk, carlitox477, catellatech, chaduke, codeislight, deadrxsezzz, descharre, erictee, fatherOfBlocks, favelanky, glcanvas, handsomegiraffe, jasonxiale, jekapi, joestakey, lemonr, luxartvinsec, martin, matrix_0wl, minhquanym, mrpathfindr, nadin, oyc_109, parsely, peanuts, pfedprog, rbserver, rokso, saian, santipu_, scokaf, slvDev, tsvetanovv, ubl4nk, ulqiorra, yamapyblack, zaskoh
29.6697 USDC - $29.67
In BYTES2 contract in function upgradeBytes
it's possible to mint zero amount of tokens.
https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L93-L106
This might be uncomfortable and misleading.
Please, fix typos:
This improves readability, replace 100 to ONE_HUNDERD_PERCENT or any meaningful name
https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L1022 https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L1098 https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L1155 https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L1389 https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L1623
Please rewrite https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L1022
to just:
citizenStatus.points = timelockMultiplier;
This statements are similar.
And rewrite https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/BYTES2.sol#L1029
to:
pool.totalPoints += timelockMultiplier
Why use two divisions, looks like only one needed for vaultMultiplier
.
And correct expression is:
citizenStatus.points = identityPoints * vaultMultiplier * timelockMultiplier / _DIVISOR;
#0 - c4-judge
2023-03-17T02:57:30Z
hansfriese marked the issue as grade-b
🌟 Selected for report: JCN
Also found by: 0x1f8b, 0xSmartContract, 0xSolus, 0xhacksmithh, 0xnev, Angry_Mustache_Man, Aymen0909, Diana, Flora, Inspex, Madalad, MatricksDeCoder, MiniGlome, R-Nemes, RaymondFam, ReyAdmirado, Rolezn, SAAJ, Sathish9098, Shubham, Udsen, Viktor_Cortess, arialblack14, atharvasama, ayden, c3phas, carlitox477, descharre, dharma09, durianSausage, fatherOfBlocks, ginlee, glcanvas, hunter_w3b, leopoldjoy, matrix_0wl, mrpathfindr, nadin, oyc_109, pipoca, schrodinger, slvDev, ulqiorra, volodya
19.3029 USDC - $19.30
Optimize getPoolReward
function.
In current implementation we iterate over whole array of StakedS1Citizen items for _recipient to calculate points.
Like here:
https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/NeoTokyoStaker.sol#L1279-L1286
and here:
https://github.com/code-423n4/2023-03-neotokyo/blob/main/contracts/staking/NeoTokyoStaker.sol#L1288-L1295
But we can use additional mapping: mapping(address => uint256) pointStakedS1Citizen
(same for S2Citizen), where placed total points per user. This mapping must be updated when we:
And therefore, to calculate total user's points in the function getPoolReward
we can just read value from the storage.
This optimization needed, because adding/deletion token is rare while getPoolReward
might be called often.
Optimize getPoolReward
function.
In current implementation we iterate over whole list of windows. But, by design -- rewards amount increases during window iteration. Time complexity here is O(n). But we can improve this complexity to O(log(N)) use binary search, and storing in windows sum on prefixes.
So, in improvement version we do next:
last_window.cumulative_amount - first_unprocessed_window.cumulative_amount
.configurePools
sum-up windows and write cumulative value or on the admin side pre-calculate required values and pass them
directly.This optimization needed, because getPoolReward
might be called very often, and it's not needed to iterate over whole windows each time.
#0 - c4-judge
2023-03-17T03:54:38Z
hansfriese marked the issue as grade-b