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: 152/169
Findings: 1
Award: $35.48
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
VaultController.sol#L456, BeefyAdapter.sol#L80, BeefyAdapter.sol#L83, YearnAdapter.sol#L54
There is no logic to revoke these approvals (e.i. approve to zero). In the case of the address()
has some bugs, it may be desirable to be able to revoke the approvals.
VaultController.sol#L456
IERC20(rewardsToken).approve(staking, type(uint256).max);
BeefyAdapter.sol#L80, BeefyAdapter.sol#L83
IERC20(asset()).approve(_beefyVault, type(uint256).max); IERC20(_beefyVault).approve(_beefyBooster, type(uint256).max);
IERC20(_asset).approve(address(yVault), type(uint256).max);
Consider implementing an approval to 0
.
safeApprove()
OpenZeppelin safeApprove()
implementation is deprecated. Reference. Using this deprecated function can lead to unintended reverts and potential locking of funds.
rewardToken.safeApprove(address(escrow), type(uint256).max);
Consider replacing safeApprove()
with safeIncreaseAllowance()
or safeDecreaseAllowance()
instead regarding Openzeppelin comment.
- rewardToken.safeApprove(address(escrow), type(uint256).max); + rewardToken.safeDecreaseAllowance(address(escrow), type(uint256).max);
pragma
versionPresent in most files.
Contracts should be deployed using a fixed pragma
version. Locking the pragma helps to ensure that
contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce
bugs that affect the contract system negatively
Lock the pragma version and also consider upgrading the project pragma version to a newer stable version, currently 0.8.10.
Present in most files.
Some of the contract's constructor
variables and functions are missing natespec comments.
Consider adding the missing natspec comments.
bytes.concat
instead of abi.encodePacked
for concatenationMultiRewardEscrow.sol#L104, MultiRewardStaking.sol#L49-L50, MultiRewardStaking.sol#L459-L479
While one of the uses of abi.encodePacked
is to perform concatenation, the Solidity language does
contain a reserved function for this: bytes.concat
.
Consider using bytes.concat instead of abi.encodePacked for concatenation:
MultiRewardEscrow.sol#L104
- bytes32 id = keccak256(abi.encodePacked(token, account, amount, nonce)); + bytes32 id = keccak256(bytes.concat(token, account, amount, nonce));
MultiRewardStaking.sol#L49-L50
- _name = string(abi.encodePacked("Staked ", IERC20Metadata(address(_stakingToken)).name())); - _symbol = string(abi.encodePacked("pst-", IERC20Metadata(address(_stakingToken)).symbol())); + _name = string(bytes.concat("Staked ", IERC20Metadata(address(_stakingToken)).name())); + _symbol = string(bytes.concat("pst-", IERC20Metadata(address(_stakingToken)).symbol()));
MultiRewardStaking.sol#L459-L479
address recoveredAddress = ecrecover( keccak256( - abi.encodePacked( + bytes.concat( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s );
The test coverage rate of the project is not fulfilled. Testing all functions is best practice in terms of security criteria.
| File | % Lines | % Statements | % Branches | % Func s | |-------------------------------------------------------------------------------------|-------------------|--------------------|------------------|------- -----------| | node_modules/@openzeppelin/contracts/proxy/Clones.sol | 0.00% (0/6) | 0.00% (0/6) | 0.00% (0/4) | 0.00% (0/4) | | node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol | 83.64% (46/55) | 80.65% (50/62) | 45.45% (10/22) | 77.78% (14/18) | | node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol | 0.00% (0/17) | 0.00% (0/23) | 0.00% (0/10) | 0.00% (0/7) | | node_modules/@openzeppelin/contracts/utils/Address.sol | 0.00% (0/26) | 0.00% (0/28) | 0.00% (0/16) | 0.00% (0/13) | | node_modules/@openzeppelin/contracts/utils/Context.sol | 50.00% (1/2) | 50.00% (1/2) | 100.00% (0/0) | 50.00% (1/2) | | node_modules/@openzeppelin/contracts/utils/Strings.sol | 0.00% (0/18) | 0.00% (0/25) | 0.00% (0/4) | 0.00% (0/4) | | node_modules/@openzeppelin/contracts/utils/math/Math.sol | 6.09% (7/115) | 5.69% (7/123) | 2.08% (1/48) | 14.29% (2/14) | | node_modules/openzeppelin-upgradeable/proxy/utils/Initializable.sol | 0.00% (0/4) | 0.00% (0/4) | 0.00% (0/4) | 0.00% (0/1) | | node_modules/openzeppelin-upgradeable/security/PausableUpgradeable.sol | 100.00% (9/9) | 100.00% (9/9) | 75.00% (3/4) | 100.00 % (7/7) | | node_modules/openzeppelin-upgradeable/security/ReentrancyGuardUpgradeable.sol | 0.00% (0/2) | 0.00% (0/2) | 100.00% (0/0) | 0.00% (0/2) | | node_modules/openzeppelin-upgradeable/token/ERC20/ERC20Upgradeable.sol | 68.97% (40/58) | 67.69% (44/65) | 31.82% (7/22) | 80.00% (16/20) | | node_modules/openzeppelin-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol | 76.74% (33/43) | 77.55% (38/49) | 40.00% (4/10) | 69.57% (16/23) | | node_modules/openzeppelin-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol | 0.00% (0/17) | 0.00% (0/23) | 0.00% (0/10) | 0.00% (0/7) | | node_modules/openzeppelin-upgradeable/utils/AddressUpgradeable.sol | 0.00% (0/19) | 0.00% (0/21) | 0.00% (0/14) | 0.00% (0/9) | | node_modules/openzeppelin-upgradeable/utils/ContextUpgradeable.sol | 50.00% (1/2) | 50.00% (1/2) | 100.00% (0/0) | 25.00% (1/4) | | node_modules/openzeppelin-upgradeable/utils/math/MathUpgradeable.sol | 0.00% (0/69) | 0.00% (0/73) | 0.00% (0/24) | 0.00% (0/8) | | src/utils/EIP165.sol | 100.00% (0/0) | 100.00% (0/0) | 100.00% (0/0) | 0.00% (0/1) | | src/utils/MultiRewardEscrow.sol | 100.00% (42/42) | 88.33% (53/60) | 55.56% (10/18) | 100.00 % (9/9) | | src/utils/MultiRewardStaking.sol | 100.00% (110/110) | 89.78% (123/137) | 63.04% (29/46) | 100.00 % (26/26) | | src/utils/Owned.sol | 100.00% (7/7) | 100.00% (7/7) | 75.00% (3/4) | 100.00 % (3/3) | | src/utils/OwnedUpgradeable.sol | 40.00% (4/10) | 40.00% (4/10) | 33.33% (2/6) | 50.00% (2/4) | | src/vault/AdminProxy.sol | 100.00% (1/1) | 100.00% (1/1) | 100.00% (0/0) | 100.00 % (1/1) | | src/vault/CloneFactory.sol | 100.00% (5/5) | 100.00% (6/6) | 100.00% (4/4) | 100.00 % (1/1) | | src/vault/CloneRegistry.sol | 66.67% (4/6) | 66.67% (4/6) | 100.00% (0/0) | 33.33% (1/3) | | src/vault/DeploymentController.sol | 100.00% (13/13) | 93.33% (14/15) | 50.00% (1/2) | 100.00 % (6/6) | | src/vault/PermissionRegistry.sol | 100.00% (8/8) | 83.33% (10/12) | 50.00% (2/4) | 100.00 % (3/3) | | src/vault/TemplateRegistry.sol | 100.00% (18/18) | 80.00% (16/20) | 50.00% (4/8) | 100.00 % (6/6) | | src/vault/Vault.sol | 90.00% (108/120) | 84.83% (123/145) | 57.14% (24/42) | 88.57% (31/35) | | src/vault/VaultController.sol | 98.87% (175/177) | 88.21% (247/280) | 52.56% (41/78) | 100.00 % (42/42) | | src/vault/VaultRegistry.sol | 60.00% (6/10) | 63.64% (7/11) | 100.00% (2/2) | 33.33% (2/6) | | src/vault/adapter/abstracts/AdapterBase.sol | 95.74% (90/94) | 91.96% (103/112) | 70.83% (17/24) | 76.32% (29/38) | | src/vault/adapter/abstracts/WithRewards.sol | 0.00% (0/1) | 0.00% (0/1) | 100.00% (0/0) | 0.00% (0/3) | | src/vault/adapter/beefy/BeefyAdapter.sol | 80.85% (38/47) | 79.31% (46/58) | 55.00% (11/20) | 69.23% (9/13) | | src/vault/adapter/yearn/YearnAdapter.sol | 92.86% (26/28) | 86.11% (31/36) | 50.00% (4/8) | 92.31% (12/13) | | src/vault/strategy/Pool2SingleAssetCompounder.sol | 0.00% (0/28) | 0.00% (0/47) | 0.00% (0/4) | 0.00% (0/3) | | src/vault/strategy/RewardsClaimer.sol | 0.00% (0/9) | 0.00% (0/15) | 100.00% (0/0) | 0.00% (0/1) | | src/vault/strategy/StrategyBase.sol | 0.00% (0/4) | 0.00% (0/9) | 0.00% (0/4) | 0.00% (0/4) | | test/utils/EnhancedTest.sol | 0.00% (0/38) | 0.00% (0/42) | 0.00% (0/16) | 0.00% (0/4) | | test/utils/Faucet.sol | 0.00% (0/27) | 0.00% (0/29) | 100.00% (0/0) | 0.00% (0/8) | | test/utils/mocks/ClonableWithInitData.sol | 100.00% (1/1) | 100.00% (1/1) | 100.00% (0/0) | 100.00 % (1/1) | | test/utils/mocks/ClonableWithoutInitData.sol | 100.00% (2/2) | 100.00% (2/2) | 100.00% (0/0) | 100.00 % (2/2) | | test/utils/mocks/MockAdapter.sol | 100.00% (11/11) | 100.00% (11/11) | 100.00% (2/2) | 100.00 % (6/6) | | test/utils/mocks/MockERC20.sol | 66.67% (2/3) | 66.67% (2/3) | 100.00% (0/0) | 66.67% (2/3) | | test/utils/mocks/MockERC4626.sol | 70.00% (28/40) | 67.39% (31/46) | 50.00% (4/8) | 50.00% (9/18) | | test/utils/mocks/MockStrategy.sol | 100.00% (4/4) | 100.00% (4/4) | 100.00% (0/0) | 100.00 % (4/4) | | test/vault/integration/abstract/PropertyTest.prop.sol | 0.00% (0/86) | 0.00% (0/126) | 0.00% (0/8) | 0.00% (0/16) | | test/vault/integration/beefy/BeefyTestConfigStorage.sol | 100.00% (2/2) | 100.00% (2/2) | 100.00% (0/0) | 100.00 % (2/2) | | test/vault/integration/beefy/BeefyVault.t.sol | 7.69% (2/26) | 6.45% (2/31) | 100.00% (0/0) | 0.00% (0/5) | | test/vault/integration/yearn/YearnTestConfigStorage.sol | 100.00% (2/2) | 100.00% (2/2) | 100.00% (0/0) | 100.00 % (2/2) | | test/vault/integration/yearn/YearnVault.t.sol | 7.14% (1/14) | 6.25% (1/16) | 100.00% (0/0) | 0.00% (0/5) | | Total | 58.17% (847/1456) | 55.11% (1003/1820) | 37.00% (185/500) | 60.91% (268/440) |
Test coverage is expected to be 100%.
The specified function does not follow the guideline and grammar adopted throughout the rest of the protocol.
Use camel case for all functions, parameters and variables and snake case for constants.
- function PermissionRegistry() external view returns (IPermissionRegistry); + function permissionRegistry() external view returns (IPermissionRegistry);
MultiRewardStaking.sol#L274, YearnAdapter.sol#L25
Scientific notation should be used for better code readability.
Change the line of code as mentioned below:
MultiRewardStaking.sol#L274
- uint64 ONE = (10**IERC20Metadata(address(rewardToken)).decimals()).safeCastTo64(); + uint64 ONE = (10eIERC20Metadata(address(rewardToken)).decimals()).safeCastTo64();
- uint256 constant DEGRADATION_COEFFICIENT = 10**18; + uint256 constant DEGRADATION_COEFFICIENT = 10e18;
Pragma
version ^0.8.15 is too recent to be trustedPresent in most files.
Scientific notation should be used for better code readability.
0.8.17 (2022-09-08)
0.8.16 (2022-08-08)
0.8.15 (2022-06-15)
0.8.10 (2021-11-09)
Unexpected bugs can be reported in recent versions.
Risks related to recent releases.
Risks of complex code generation changes.
Risks of new language features.
Risks of known bugs.
Use a non-legacy and more battle-tested version. Use 0.8.10.
Vault.sol#L35, Vault.sol#L466, Vault.sol#L619
Scientific notation should be used for better code readability.
Change the line of code as mentioned below:
MultiRewardStaking.sol#L274
- uint256 constant SECONDS_PER_YEAR = 365.25 days; + uint256 constant SECONDS_PER_YEAR = 365.25 days; // 31_536_000 ( 365.25 * 24 * 60 * 60) - uint256 public highWaterMark = 1e18; + uint256 public highWaterMark = 1e18; // 1_000_000_000_000_000_000 - uint256 public quitPeriod = 3 days; + uint256 public quitPeriod = 3 days; // 259_200 ( 3 * 24 * 60 * 60)
Present in most files.
Order of Functions; ordering helps readers identify which functions they can call and to find the constructor and fallback definitions easier. But there are contracts in the project that do not comply with this.
https://docs.soliditylang.org/en/v0.8.17/style-guide.html
Functions should be grouped according to their visibility and ordered:
#0 - c4-judge
2023-02-28T15:02:33Z
dmvt marked the issue as grade-b