Platform: Code4rena
Start Date: 21/06/2022
Pot Size: $50,000 USDC
Total HM: 31
Participants: 99
Period: 5 days
Judges: moose-code, JasoonS, denhampreen
Total Solo HM: 17
Id: 139
League: ETH
Rank: 67/99
Findings: 2
Award: $79.72
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1337, 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xNineDec, 0xc0ffEE, 0xf15ers, 0xmint, Bnke0x0, BowTiedWardens, Chom, ElKu, FudgyDRS, Funen, GalloDaSballo, GimelSec, JC, Kaiziron, Lambda, Limbooo, Metatron, MiloTruck, Noah3o6, Picodes, PumpkingWok, PwnedNoMore, Sm4rty, StErMi, TomJ, TrungOre, UnusualTurtle, Waze, _Adam, aga7hokakological, ak1, antonttc, berndartmueller, cccz, cryptphi, csanuragjain, defsec, delfin454000, dipp, elprofesor, exd0tpy, fatherOfBlocks, hake, hansfriese, hubble, joestakey, kenta, ladboy233, mics, oyc_109, pashov, pedr02b2, reassor, robee, samruna, scaraven, shung, sikorico, simon135, sseefried, tchkvsky, unforgiven, zzzitron
53.1414 USDC - $53.14
affiliateFee
should have an upper limit to avoid abuse.b) @dev this allows us to change how much time before the end of the cycle we send the withdraw requests should be "we can send" and not "we send"
a) asdf
b) // try to claim withdraw if user has withdraws to claim function will check if withdraw is valid
🌟 Selected for report: BowTiedWardens
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xmint, 8olidity, ACai, Bnke0x0, Chom, ElKu, Fabble, Fitraldys, FudgyDRS, Funen, GalloDaSballo, GimelSec, IllIllI, JC, Kaiziron, Lambda, Limbooo, MiloTruck, Noah3o6, Nyamcil, Picodes, PwnedNoMore, Randyyy, RedOneN, Sm4rty, StErMi, TomJ, Tomio, TrungOre, UnusualTurtle, Waze, _Adam, aga7hokakological, ajtra, antonttc, asutorufos, bardamu, c3phas, defsec, delfin454000, exd0tpy, fatherOfBlocks, hansfriese, ignacio, joestakey, kenta, ladboy233, m_Rassska, mics, minhquanym, oyc_109, pashov, reassor, robee, s3cunda, sach1r0, saian, sashik_eth, scaraven, sikorico, simon135, slywaters
26.5777 USDC - $26.58
References where this could be done are:
a. Staking.sol
:
on lines 143 , 408 , 410 , 527 , 572 , 574 , 586 , 604-614 , 644 and 676.
b. Yieldy.sol
:
on lines 58-59 , 83 , 96 , 187, 190 , 210 , 249 , 257 , 279 and 286.
c. LiquidityReserve.sol:
on lines 25, 44, 61, 62, 68, 94, 105, 163, 170, 192 and 215.
a. Claim memory info = warmUpInfo[_recipient]; return epoch.number >= info.expiry && info.expiry != 0;
Three slots(struct Claim contains three uint256) are read here while only one slot is used in the function. This will save 200 gas.
b. Claim memory info = warmUpInfo[_recipient];
The whole structure is read while only the Claim.credits element is needed. Also this statement should be put inside the if statement, just above the delete statement on line 468.
a. withdrawalAmount.
b. Use currentTotalSupply instead of _totalSupply. It will save 100-3=97 gas. require(_totalSupply > 0, "Can't rebase if not circulating");
c. Cache _totalSupply in _storeRebase function
d. Cache creditBalances[msg.sender] in transfer function
a. _isClaimWithdrawAvailable function in Staking.sol
function _isClaimWithdrawAvailable(address _recipient) internal returns (bool) { Claim memory info = coolDownInfo[_recipient]; ITokeManager tokeManager = ITokeManager(TOKE_MANAGER); ITokePool tokePoolContract = ITokePool(TOKE_POOL); RequestedWithdrawalInfo memory requestedWithdrawals = tokePoolContract .requestedWithdrawals(address(this)); uint256 currentCycleIndex = tokeManager.getCurrentCycleIndex(); return epoch.number >= info.expiry && info.expiry != 0 && info.amount != 0 && ((requestedWithdrawals.minCycle <= currentCycleIndex && requestedWithdrawals.amount + withdrawalAmount >= info.amount) || withdrawalAmount >= info.amount); }
Can be rewritten as:
function _isClaimWithdrawAvailable(address _recipient) internal returns (bool) { Claim memory info = coolDownInfo[_recipient]; //by bringing some statements up here, we might save a large amount of gas in some cases. if(epoch.number < info.expiry || info.expiry == 0 || info.amount == 0) { return false; } ITokeManager tokeManager = ITokeManager(TOKE_MANAGER); ITokePool tokePoolContract = ITokePool(TOKE_POOL); RequestedWithdrawalInfo memory requestedWithdrawals = tokePoolContract .requestedWithdrawals(address(this)); uint256 currentCycleIndex = tokeManager.getCurrentCycleIndex(); uint256 w = withdrawalAmount; //cache the storage variable. return //notice how I have swapped the 1st and 2nd condition of OR. //If first condition is true, then we will save gas on 2nd condition. (w >= info.amount || (requestedWithdrawals.minCycle <= currentCycleIndex && requestedWithdrawals.amount + w >= info.amount)); }
b. Function canBatchTransactions() can be rewritten as:
function canBatchTransactions() public view returns (bool) { if (requestWithdrawalAmount == 0) { //least dependent on calculations. return false; } ITokeManager tokeManager = ITokeManager(TOKE_MANAGER); uint256 currentCycleIndex = tokeManager.getCurrentCycleIndex(); if (currentCycleIndex <= lastTokeCycleIndex) { //needs relatively less calculation than next one. return false; } uint256 duration = tokeManager.getCycleDuration(); uint256 currentCycleStart = tokeManager.getCurrentCycle(); uint256 nextCycleStart = currentCycleStart + duration; return block.timestamp + timeLeftToRequestWithdrawal >= nextCycleStart; //depends on many calculations }
References include: a. ITokeReward tokeRewardContract = ITokeReward(TOKE_REWARD); b. ITokeManager tokeManager = ITokeManager(TOKE_MANAGER); ITokePool tokePoolContract = ITokePool(TOKE_POOL); c. ITokeManager tokeManager = ITokeManager(TOKE_MANAGER); d. ITokePool tokePoolContract = ITokePool(TOKE_POOL); e. ITokePool tokePoolContract = ITokePool(TOKE_POOL); f. ITokePool tokePoolContract = ITokePool(TOKE_POOL); g. ITokePool tokePoolContract = ITokePool(TOKE_POOL); h. ITokeManager tokeManager = ITokeManager(TOKE_MANAGER); i. uint256 currentCycleIndex = tokeManager.getCurrentCycleIndex();
When emitting messages, if the variable is available in memory, use it, rather than the storage variable(which in most cases is just assigned from the memory variable)
emit LogSetCurvePool(CURVE_POOL, curvePoolTo, curvePoolFrom);
Redundant code logic should be removed. This if statement will never return true.
Because the require statement on line 528 says _amount <= walletBalance + warmUpBalance.
rebasingCreditsPerToken = rebasingCredits / updatedTotalSupply; require(rebasingCreditsPerToken > 0, "Invalid change in supply");
to
require(rebasingCredits > updatedTotalSupply, "Invalid change in supply"); rebasingCreditsPerToken = rebasingCredits / updatedTotalSupply;
for (uint256 i; i < contractsLength; ) { if (contracts[i] == _address) { delete contracts[i]; } unchecked { ++i; } }