Platform: Code4rena
Start Date: 16/02/2023
Pot Size: $144,750 USDC
Total HM: 17
Participants: 154
Period: 19 days
Judge: Trust
Total Solo HM: 5
Id: 216
League: ETH
Rank: 146/154
Findings: 1
Award: $42.07
π Selected for report: 0
π Solo Findings: 0
π Selected for report: c3phas
Also found by: 0x3b, 0x6980, 0x73696d616f, 0xSmartContract, 0xackermann, 0xhacksmithh, 0xsomeone, Bnke0x0, Bough, Budaghyan, Darshan, DeFiHackLabs, Deivitto, GalloDaSballo, JCN, LethL, Madalad, MiniGlome, Morraez, P-384, PaludoX0, Phantasmagoria, Praise, RHaO-sec, Rageur, RaymondFam, ReyAdmirado, Rickard, Rolezn, SaeedAlipoor01988, Saintcode_, Sathish9098, TheSavageTeddy, Tomio, Viktor_Cortess, abiih, arialblack14, atharvasama, banky, codeislight, cryptonue, ddimitrov22, dec3ntraliz3d, descharre, dharma09, emmac002, favelanky, hl_, hunter_w3b, kaden, kodyvim, matrix_0wl, oyc_109, pavankv, scokaf, seeu, yamapyblack
42.0697 USDC - $42.07
actualWithdrawn
be calculated without using balanceOf
or another storage access?In order to compute actualWithdrawn
, balanceOf
is run in a loop.
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L386
balanceOf
is also executed twice in the same loop.
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L373
If actualWithdrawn
can be calculated in another way, balanceOf
in a loop is omitted and the code around here can be simplified.
IStrategy
's withdraw
had better return loss and actualWithdrawn
.
IStrategy
function withdraw(uint256 _amount) external returns (uint256 loss, uint256 actualWithdrawn);
ReaperBaseStrategyv4.sol (implementation)
function withdraw(uint256 _amount) external override returns (uint256 loss, uint256 amountFreed) {
The entire loop looks like the following.
uint256 vaultBalance = token.balanceOf(address(this)); for (uint256 i = 0; i < queueLength; i = i.uncheckedInc()) { if (value <= vaultBalance) { break; } address stratAddr = withdrawalQueue[i]; uint256 strategyBal = strategies[stratAddr].allocated; if (strategyBal == 0) { continue; } uint256 remaining = value - vaultBalance; (uint256 loss, uint256 actualWithdrawn) = IStrategy(stratAddr).withdraw(Math.min(remaining, strategyBal)); vaultBalance -= actualWithdrawn; // Withdrawer incurs any losses from withdrawing as reported by strat if (loss != 0) { value -= loss; totalLoss += loss; _reportLoss(stratAddr, loss); } strategies[stratAddr].allocated -= actualWithdrawn; totalAllocated -= actualWithdrawn; }
uint256 balBefore = token.balanceOf(address(this)); token.safeTransferFrom(msg.sender, address(this), _amount); uint256 balAfter = token.balanceOf(address(this)); _amount = balAfter - balBefore;
As the reduced amount always matches _amount, there is no need to calculate balBefore and balAfter. The above four lines can be simplified to the following one line.
token.safeTransferFrom(msg.sender, address(this), _amount);
name
and symbol
arenβt necessary to cast stringhttps://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L119
ERC20(string(_name), string(_symbol))
ERC20(_name, _symbol)
debt
can be simplified by the ternary operatorWhen assigning to variables with if statement, the ternary operator would be useful.
uint256 debt = availableCapital < 0 ? uint256(-availableCapital) : 0;
#0 - c4-judge
2023-03-09T18:15:46Z
trust1995 marked the issue as grade-b