Platform: Code4rena
Start Date: 31/01/2023
Pot Size: $90,500 USDC
Total HM: 47
Participants: 169
Period: 7 days
Judge: LSDan
Total Solo HM: 9
Id: 211
League: ETH
Rank: 55/169
Findings: 4
Award: $221.66
π Selected for report: 0
π Solo Findings: 0
61.303 USDC - $61.30
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/VaultController.sol#L669
The function is expected to revert only if the caller is neither the submitter nor the owner. But the current condition requires that the caller should be the submitter as well as the owner.
if (msg.sender != metadata.creator || msg.sender != owner) revert NotSubmitterNorOwner(msg.sender);
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/VaultController.sol#L669
Manual Review
Should use &&
instead of ||
. Like follwing.
if (msg.sender != metadata.creator && msg.sender != owner) revert NotSubmitterNorOwner(msg.sender);
#0 - c4-judge
2023-02-16T07:24:05Z
dmvt marked the issue as duplicate of #45
#1 - c4-sponsor
2023-02-18T12:08:18Z
RedVeil marked the issue as disagree with severity
#2 - c4-sponsor
2023-02-18T12:08:33Z
RedVeil marked the issue as sponsor confirmed
#3 - c4-judge
2023-02-23T00:46:14Z
dmvt marked the issue as partial-50
88.0962 USDC - $88.10
Judge has assessed an item in Issue #56 as 2 risk. The relevant finding follows:
Attribute values of fees_ could exceed 1e18 when initializing even if the proposedFees is checked in proposeFees() function. https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L88
function initialize( IERC20 asset_, IERC4626 adapter_, VaultFees calldata fees_, address feeRecipient_, address owner ) external initializer { ... fees = fees_; function proposeFees(VaultFees calldata newFees) external onlyOwner { if ( newFees.deposit >= 1e18 || newFees.withdrawal >= 1e18 || newFees.management >= 1e18 || newFees.performance >= 1e18 ) revert InvalidVaultFees();
proposedFees = newFees;
initialize() function could have a check if the attribute values of fees_ are less than 1e18.
#0 - c4-judge
2023-03-01T01:08:42Z
dmvt marked the issue as duplicate of #540
#1 - c4-judge
2023-03-01T01:31:53Z
dmvt marked the issue as not a duplicate
#2 - c4-judge
2023-03-01T01:32:14Z
dmvt marked the issue as duplicate of #396
#3 - c4-judge
2023-03-01T01:32:23Z
dmvt marked the issue as satisfactory
π Selected for report: rvierdiiev
Also found by: Lirios, Ruhum, ayeslick, bin2chen, critical-or-high, hansfriese, hashminer0725, immeas, jasonxiale, mookimgo
36.7818 USDC - $36.78
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L540-L546
proposedFees
is set to a default struct which all attribute fees are 0
when deploying the contract.
And changeFees()
function can be called by anyone.
proposedFees
is updated when the owner proposes the fees by calling proposeFees()
function.
So if the owner has not proposed the fees yet after deploying the contract, the attacker can change all fees to 0
by calling changeFees()
function.
function changeFees() external { if (block.timestamp < proposedFeeTime + quitPeriod) revert NotPassedQuitPeriod(quitPeriod); emit ChangedFees(fees, proposedFees); fees = proposedFees; }
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L540-L546
Manual Review
changeFees()
function can have onlyOwner
modifier or have a check if proposedFeeTime
is not 0
.
#0 - c4-judge
2023-02-16T08:08:49Z
dmvt marked the issue as duplicate of #78
#1 - c4-sponsor
2023-02-18T12:16:30Z
RedVeil marked the issue as disagree with severity
#2 - c4-sponsor
2023-02-18T12:16:52Z
RedVeil marked the issue as sponsor confirmed
#3 - c4-judge
2023-03-01T00:20:08Z
dmvt marked the issue as satisfactory
#4 - c4-judge
2023-03-01T22:32:17Z
dmvt changed the severity to 2 (Med Risk)
π Selected for report: rvierdiiev
Also found by: Lirios, Ruhum, ayeslick, bin2chen, critical-or-high, hansfriese, hashminer0725, immeas, jasonxiale, mookimgo
36.7818 USDC - $36.78
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/VaultController.sol#L372-L381
proposedFees
of vaults are set to a default struct which all attribute fees are 0
when deploying the vault contracts.
If the creator has not proposed the fees yet after deploying the vaults, the attacker can change the fees of vaults to 0
by calling changeVaultFees()
function.
function changeVaultFees(address[] calldata vaults) external { uint8 len = uint8(vaults.length); for (uint8 i = 0; i < len; i++) { (bool success, bytes memory returnData) = adminProxy.execute( vaults[i], abi.encodeWithSelector(IVault.changeFees.selector) ); if (!success) revert UnderlyingError(returnData); } }
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/VaultController.sol#L372-L381
Manual Review
It can have a check if the caller is the creator of the vault to be updated.
for (uint8 i = 0; i < len; i++) { _verifyCreator(vaults[i]); (bool success, bytes memory returnData) = adminProxy.execute( vaults[i], abi.encodeWithSelector(IVault.changeFees.selector) ); if (!success) revert UnderlyingError(returnData); }
#0 - c4-judge
2023-02-16T08:08:53Z
dmvt marked the issue as duplicate of #78
#1 - c4-sponsor
2023-02-18T12:16:32Z
RedVeil marked the issue as disagree with severity
#2 - c4-sponsor
2023-02-18T12:16:54Z
RedVeil marked the issue as sponsor confirmed
#3 - c4-judge
2023-02-23T01:01:17Z
dmvt marked the issue as partial-25
#4 - c4-judge
2023-02-23T01:18:00Z
dmvt changed the severity to 2 (Med Risk)
π Selected for report: IllIllI
Also found by: 0x3b, 0xAgro, 0xBeirao, 0xMirce, 0xNineDec, 0xRobocop, 0xSmartContract, 0xTraub, 0xWeiss, 2997ms, 41i3xn, Awesome, Aymen0909, Bauer, Bnke0x0, Breeje, Cryptor, DadeKuma, Deathstore, Deekshith99, DevABDee, DevTimSch, Dewaxindo, Diana, Ermaniwe, Guild_3, H0, IceBear, Inspectah, JDeryl, Kaiziron, Kaysoft, Kenshin, Mukund, Praise, RaymondFam, Rickard, Rolezn, Ruhum, Sathish9098, SkyWalkerMan, SleepingBugs, UdarTeam, Udsen, Walter, aashar, adeolu, apvlki, arialblack14, ast3ros, btk, chaduke, chandkommanaboyina, chrisdior4, climber2002, codetilda, cryptonue, cryptostellar5, csanuragjain, ddimitrov22, descharre, dharma09, doublesharp, eccentricexit, ethernomad, fs0c, georgits, halden, hansfriese, hashminer0725, immeas, lukris02, luxartvinsec, matrix_0wl, merlin, mookimgo, mrpathfindr, nadin, olegthegoat, pavankv, rbserver, rebase, savi0ur, sayan, scokaf, seeu, shark, simon135, tnevler, tsvetanovv, ulqiorra, ustas, waldenyan20, y1cunhui, yongskiws, yosuke
35.4779 USDC - $35.48
success
could be defined in the first if
conditionhttps://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/CloneFactory.sol#L42
bool success = true; if (template.requiresInitData) (success, ) = clone.call(data); if (!success) revert DeploymentInitFailed();
success
could be defined in the first if
condition. If template.requiresInitData
is false
, checking !success
is unnecessary.
fees_
could exceed 1e18 when initializing even if the proposedFees
is checked in proposeFees()
function.https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L88
function initialize( IERC20 asset_, IERC4626 adapter_, VaultFees calldata fees_, address feeRecipient_, address owner ) external initializer { ... fees = fees_;
function proposeFees(VaultFees calldata newFees) external onlyOwner { if ( newFees.deposit >= 1e18 || newFees.withdrawal >= 1e18 || newFees.management >= 1e18 || newFees.performance >= 1e18 ) revert InvalidVaultFees(); proposedFees = newFees;
initialize()
function could have a check if the attribute values of fees_
are less than 1e18
.
convertToShares()
function is used twice.https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L143 https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L147
uint256 feeShares = convertToShares( assets.mulDiv(uint256(fees.deposit), 1e18, Math.Rounding.Down) ); shares = convertToShares(assets) - feeShares;
It could calculate the share amount for asset
and then calculate feeShares
and shares
to be minted from the amount. Like doing in other functions.
assetsCheckpoint
is never used.https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L467
uint256 public assetsCheckpoint;
The variable could be removed from the contract.
_registerCreatedVault()
function doesn't need to have metadata
parmeter.https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/VaultController.sol#L144
function _registerCreatedVault( address vault, address staking, VaultMetadata memory metadata ) internal { metadata.vault = vault; metadata.staking = staking; metadata.creator = msg.sender;
metadata
is set in the function again.
/// @notice OPTIONAL - If the asset is an Lp Token these are its underlying assets address[8] swapTokenAddresses; /// @notice OPTIONAL - If the asset is an Lp Token its the pool address address swapAddress; /// @notice OPTIONAL - If the asset is an Lp Token this is the identifier of the exchange (1 = curve) uint256 exchange;
swapTokenAddresses
, swapAddress
, and exchange
are never used from the contracts.
newCooldown
can include 1 day
even if 1 day
is not allowed in VaultController.if (newCooldown >= 1 days) revert InvalidHarvestCooldown(newCooldown);
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/VaultController.sol#L793
if (newCooldown > 1 days) revert InvalidHarvestCooldown(newCooldown);
NoteSubmitter()
is never used.https://github.com/code-423n4/2023-01-popcorn/blob/main/src/utils/MultiRewardStaking.sol#L226
error NotSubmitter(address submitter);
NoFee(IERC20 token)
is never used.https://github.com/code-423n4/2023-01-popcorn/blob/main/src/utils/MultiRewardEscrow.sol#L200
error NoFee(IERC20 token);
setPermissions()
function is only reverted if both newPermissions[i].endorsed
and newPermissions[i].rejected
are true
. But it also should be reverted if both are false
.https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/PermissionRegistry.sol#L43
if (newPermissions[i].endorsed && newPermissions[i].rejected) revert Mismatch();
accrued
could be removed from the Fee
struct.https://github.com/code-423n4/2023-01-popcorn//blob/main/src/interfaces/IMultiRewardEscrow.sol#L26
24 struct Fee { 25 /// @notice Accrued fee amount 26 uint256 accrued; 27 /// @notice Fee percentage in 1e18 for 100% (1 BPS = 1e14) 28 uint256 feePerc; 29 }
It's never used from the contracts.
#0 - c4-judge
2023-03-01T00:17:58Z
dmvt marked the issue as grade-b