Platform: Code4rena
Start Date: 21/04/2022
Pot Size: $100,000 USDC
Total HM: 18
Participants: 60
Period: 7 days
Judge: gzeon
Total Solo HM: 10
Id: 112
League: ETH
Rank: 2/60
Findings: 6
Award: $15,927.75
🌟 Selected for report: 3
🚀 Solo Findings: 1
🌟 Selected for report: IllIllI
12867.0542 USDC - $12,867.05
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/CompoundHandler.sol#L71 https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/CompoundHandler.sol#L120 https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/AaveHandler.sol#L53 https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L847
OpenZeppelin's safeApprove()
will revert if the account already is approved and the new safeApprove()
is done with a non-zero value
function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); }
Customers cannot be topped up a second time, which will cause them to be liquidated even though they think they're protected
There are multiple places where safeApprove()
is called a second time without setting the value to zero first. The instances below are all related to topping up.
Compound-specific top-ups will fail the second time around when approving the ctoken
again:
File: backd/contracts/actions/topup/handlers/CompoundHandler.sol #1 50 function topUp( 51 bytes32 account, 52 address underlying, 53 uint256 amount, 54 bytes memory extra 55 ) external override returns (bool) { 56 bool repayDebt = abi.decode(extra, (bool)); 57 CToken ctoken = cTokenRegistry.fetchCToken(underlying); 58 uint256 initialTokens = ctoken.balanceOf(address(this)); 59 60 address addr = account.addr(); 61 62 if (repayDebt) { 63 amount -= _repayAnyDebt(addr, underlying, amount, ctoken); 64 if (amount == 0) return true; 65 } 66 67 uint256 err; 68 if (underlying == address(0)) { 69 err = ctoken.mint{value: amount}(amount); 70 } else { 71 IERC20(underlying).safeApprove(address(ctoken), amount);
Compound-specific top-ups will also fail when trying to repay debt:
File: backd/contracts/actions/topup/handlers/CompoundHandler.sol #2 62 if (repayDebt) { 63 amount -= _repayAnyDebt(addr, underlying, amount, ctoken); 64 if (amount == 0) return true; 65 }
Aave-specific top-ups will fail for the lendingPool
:
File: backd/contracts/actions/topup/handlers/AaveHandler.sol #3 36 function topUp( 37 bytes32 account, 38 address underlying, 39 uint256 amount, 40 bytes memory extra 41 ) external override returns (bool) { 42 bool repayDebt = abi.decode(extra, (bool)); 43 if (underlying == address(0)) { 44 weth.deposit{value: amount}(); 45 underlying = address(weth); 46 } 47 48 address addr = account.addr(); 49 50 DataTypes.ReserveData memory reserve = lendingPool.getReserveData(underlying); 51 require(reserve.aTokenAddress != address(0), Error.UNDERLYING_NOT_SUPPORTED); 52 53 IERC20(underlying).safeApprove(address(lendingPool), amount);
The TopUpAction
itself fails for the feeHandler
:
File: backd/contracts/actions/topup/TopUpAction.sol #4 840 function _payFees( 841 address payer, 842 address beneficiary, 843 uint256 feeAmount, 844 address depositToken 845 ) internal { 846 address feeHandler = getFeeHandler(); 847 IERC20(depositToken).safeApprove(feeHandler, feeAmount);
I've filed the other less-severe instances as a separate medium-severity issue, and flagged the remaining low-severity instances in my QA report
Code inspection
Always do safeApprove(0)
if the allowance is being changed, or use safeIncreaseAllowance()
#0 - chase-manning
2022-05-11T14:55:30Z
🌟 Selected for report: Dravee
Also found by: IllIllI, MaratCerby, UnusualTurtle, WatchPug, antonttc, berndartmueller, cccz, danb, horsefacts, hyh, pauliax, rayn, wuwe1
The use of payable.transfer()
is heavily frowned upon because it can lead to the locking of funds. The transfer()
call requires that the recipient has a payable
callback, only provides 2300 gas for its operation. This means the following cases can cause the transfer to fail:
payable
callbackpayable
callback spends more than 2300 gas (which is only enough to emit something)Customers using non-EOA accounts with their positions cannot redeem()
their LP tokens if the account has anything more than a basic receive() payable
callback
redeem()
calls _doTransferOut()
using the msg.sender
...
File: backd/contracts/pool/LiquidityPool.sol 567 _doTransferOut(payable(msg.sender), redeemUnderlying);
which uses payable.transfer()
to send back out Ether:
File: backd/contracts/pool/EthPool.sol 30 to.transfer(amount);
Note that there are a lot of other payable.transfer()
instances, but none of them interact with users, only governance, vaults, and strategies, so I've split those off to my QA report
Code inspection
Use msg.sender.call{value:x}()
to send Ether
#0 - chase-manning
2022-04-28T11:39:38Z
Duplicate of #52
1042.2314 USDC - $1,042.23
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L50 https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/LiquidityPool.sol#L721
OpenZeppelin's safeApprove()
will revert if the account already is approved and the new safeApprove()
is done with a non-zero value
function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); }
Customers can be prevented from register()
ing the same token
/stakerVaultAddress
as another customer; and once changed away from, stakers and lptokens can't be used in the future.
There are multiple places where safeApprove()
is called a second time without setting the value to zero first.
register()
calls lockFunds()
for each user registration, and since users will use the same tokens and staker vaults, the second user's register()
call will fail:
File: backd/contracts/actions/topup/TopUpAction.sol #1 36 function lockFunds( 37 address stakerVaultAddress, 38 address payer, 39 address token, 40 uint256 lockAmount, 41 uint256 depositAmount 42 ) external { 43 uint256 amountLeft = lockAmount; 44 IStakerVault stakerVault = IStakerVault(stakerVaultAddress); 45 46 // stake deposit amount 47 if (depositAmount > 0) { 48 depositAmount = depositAmount > amountLeft ? amountLeft : depositAmount; 49 IERC20(token).safeTransferFrom(payer, address(this), depositAmount); 50 IERC20(token).safeApprove(stakerVaultAddress, depositAmount);
The changing of either the staker or an lp token is behind a time-lock, and once the time has passed, the changed variables rely on this function:
File: backd/contracts/pool/LiquidityPool.sol #2 717 function _approveStakerVaultSpendingLpTokens() internal { 718 address staker_ = address(staker); 719 address lpToken_ = address(lpToken); 720 if (staker_ == address(0) || lpToken_ == address(0)) return; 721 IERC20(lpToken_).safeApprove(staker_, type(uint256).max); 722 }
If a bug is found in a new staker
or lpToken
and the governor wishes to change back to the old one(s), the governor will have to wait for the time-lock delay only to find out that the old value(s) cause the code to revert.
I've filed the other more-severe instances as a separate high-severity issue, and flagged the remaining low-severity instances in my QA report
Code inspection
Always do safeApprove(0)
if the allowance is being changed, or use safeIncreaseAllowance()
#0 - samwerner
2022-05-03T17:59:56Z
It should be noted that the second example referring to _approveStakerVaultSpendingLpTokens()
is not an issue. This is neither a member variable that can be updated nor is it behind a time lock. Both the staker
and lpToken
can only be set once and hence the safeApprove
in the aforementioned function can only be called once.
#1 - chase-manning
2022-05-11T15:05:03Z
🌟 Selected for report: cccz
Also found by: 0x1f8b, 0xDjango, 0xkatana, Dravee, IllIllI, WatchPug, berndartmueller, defsec, horsefacts, hyh, kenta, rayn, reassor, sorrynotsorry
58.8714 USDC - $58.87
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/oracles/ChainlinkUsdWrapper.sol#L64 https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/oracles/ChainlinkOracleProvider.sol#L55
If the oracle price feeds are insufficiently validated, there will be pricing errors leading to the miss-pricing of assets/risk
The code does not verify that answeredInRound >= roundID
for both cases where an oracle is used, and the timestamp isn't checked for the Eth oracle, because the return values are ignored:
File: backd/contracts/oracles/ChainlinkUsdWrapper.sol #1 64 (, int256 answer, , , ) = _ethOracle.latestRoundData();
File: backd/contracts/oracles/ChainlinkOracleProvider.sol #2 55 (, int256 answer, , uint256 updatedAt, ) = AggregatorV2V3Interface(feed).latestRoundData();
Code inspection
Fetch all return values from the call to latestRoundData()
and require()
that answeredInRound
is greater than or equal to roundID
, and that updatedAt
is not equal to zero
#0 - chase-manning
2022-04-28T11:25:57Z
Duplicate of #17
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x52, 0xDjango, 0xkatana, Dravee, Funen, Kenshin, Ruhum, StyxRave, Tadashi, TerrierLover, TrungOre, antonttc, berndartmueller, catchup, csanuragjain, defsec, dipp, fatherOfBlocks, hake, horsefacts, hubble, jayjonah8, joestakey, kebabsec, kenta, m4rio_eth, oyc_109, pauliax, peritoflores, rayn, remora, robee, securerodd, simon135, sorrynotsorry, sseefried, z3s
1551.5588 USDC - $1,551.56
Vulnerability details:
_lastWithdrawal[vault]
will always be zero for new vaults, so the check is for 0 + minWithdrawalDelay
which will always be less than block.timestamp
File: backd/contracts/vault/VaultReserve.sol #1 102 function canWithdraw(address vault) public view returns (bool) { 103 return block.timestamp >= _lastWithdrawal[vault] + minWithdrawalDelay;
AaveHandler
does not extend BaseHandler
Unlike CompoundHandler
, AaveHandler
does not extend BaseHandler
, which will cause storage problems in future versions
File: backd/contracts/actions/topup/handlers/AaveHandler.sol #1 15 contract AaveHandler is ITopUpHandler {
receive()
function will lock Ether in contractIf the intention is for the Ether to be used, the function should call another function, otherwise it should revert
File: contracts/actions/topup/TopUpAction.sol #1 176 receive() external payable { 177 // solhint-disable-previous-line no-empty-blocks 178 }
File: contracts/pool/EthPool.sol #2 10 receive() external payable {}
File: contracts/strategies/BkdEthCvx.sol #3 46 receive() external payable {}
File: contracts/strategies/StrategySwapper.sol #4 45 receive() external payable {}
File: contracts/vault/EthVault.sol #5 13 receive() external payable {}
_prepareDeadline()
, _setConfig()
, and _executeDeadline()
should be private
These functions have the ability to bypass the timelocks of every setting. No contract besides the Preparable
contract itself should need to call these functions, and having them available will lead to exploits. The contracts that currently call _setConfig()
in their constructors should be given a new function _initConfig()
for this purpose. The Vault
calls some of these functions as well, and should be changed to manually inspect the deadline rather than mucking with the internals, which is error-prone. The mappings should also be made private
, and there should be public getters to read their values
File: backd/contracts/utils/Preparable.sol #1 115 /** 116 * @notice Execute uint256 config update (with time delay enforced). 117 * @dev Needs to be called after the update was prepared. Fails if called before time delay is met. 118 * @return New value. 119 */ 120 function _executeUInt256(bytes32 key) internal returns (uint256) { 121 _executeDeadline(key); 122 uint256 newValue = pendingUInts256[key]; 123 _setConfig(key, newValue); 124 return newValue; 125 } 126 127 /** 128 * @notice Execute address config update (with time delay enforced). 129 * @dev Needs to be called after the update was prepared. Fails if called before time delay is met. 130 * @return New value. 131 */ 132 function _executeAddress(bytes32 key) internal returns (address) { 133 _executeDeadline(key); 134 address newValue = pendingAddresses[key]; 135 _setConfig(key, newValue); 136 return newValue; 137 }
If the initializer is not executed in the same transaction as the constructor, a malicious user can front-run the initialize()
call, forcing the contract to be redeployed. Most other initializers in this project are protected, but this one appears not to be.
File: backd/contracts/AddressProvider.sol #1 53 function initialize(address roleManager) external initializer { 54 AddressProviderMeta.Meta memory meta = AddressProviderMeta.Meta(true, true); 55 _addressKeyMetas.set(AddressProviderKeys._ROLE_MANAGER_KEY, meta.toUInt()); 56 _setConfig(AddressProviderKeys._ROLE_MANAGER_KEY, roleManager); 57 }
safeApprove()
is deprecatedDeprecated in favor of safeIncreaseAllowance()
and safeDecreaseAllowance()
File: contracts/actions/topup/handlers/AaveHandler.sol #1 53 IERC20(underlying).safeApprove(address(lendingPool), amount);
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 71 IERC20(underlying).safeApprove(address(ctoken), amount);
File: contracts/actions/topup/handlers/CompoundHandler.sol #3 120 IERC20(underlying).safeApprove(address(ctoken), debt);
File: contracts/actions/topup/TopUpAction.sol #4 50 IERC20(token).safeApprove(stakerVaultAddress, depositAmount);
File: contracts/actions/topup/TopUpAction.sol #5 847 IERC20(depositToken).safeApprove(feeHandler, feeAmount);
File: contracts/actions/topup/TopUpAction.sol #6 908 IERC20(token).safeApprove(spender, type(uint256).max);
File: contracts/CvxCrvRewardsLocker.sol #7 53 IERC20(CRV).safeApprove(CRV_DEPOSITOR, type(uint256).max);
File: contracts/CvxCrvRewardsLocker.sol #8 56 IERC20(CVX_CRV).safeApprove(CVX_CRV_STAKING, type(uint256).max);
File: contracts/CvxCrvRewardsLocker.sol #9 59 IERC20(CRV).safeApprove(CVX_CRV_CRV_CURVE_POOL, type(uint256).max);
File: contracts/CvxCrvRewardsLocker.sol #10 62 IERC20(CVX).safeApprove(CVX_LOCKER, type(uint256).max);
File: contracts/pool/LiquidityPool.sol #11 721 IERC20(lpToken_).safeApprove(staker_, type(uint256).max);
File: contracts/strategies/BkdEthCvx.sol #12 43 IERC20(lp_).safeApprove(address(_BOOSTER), type(uint256).max);
File: contracts/strategies/BkdTriHopCvx.sol #13 71 IERC20(underlying_).safeApprove(curveHopPool_, type(uint256).max);
File: contracts/strategies/BkdTriHopCvx.sol #14 72 IERC20(hopLp_).safeApprove(curvePool_, type(uint256).max);
File: contracts/strategies/BkdTriHopCvx.sol #15 73 IERC20(lp_).safeApprove(address(_BOOSTER), type(uint256).max);
File: contracts/strategies/BkdTriHopCvx.sol #16 129 IERC20(hopLp).safeApprove(curvePool_, 0);
File: contracts/strategies/BkdTriHopCvx.sol #17 130 IERC20(hopLp).safeApprove(curvePool_, type(uint256).max);
File: contracts/strategies/BkdTriHopCvx.sol #18 131 IERC20(lp_).safeApprove(address(_BOOSTER), 0);
File: contracts/strategies/BkdTriHopCvx.sol #19 132 IERC20(lp_).safeApprove(address(_BOOSTER), type(uint256).max);
File: contracts/strategies/ConvexStrategyBase.sol #20 107 _CRV.safeApprove(address(_strategySwapper), type(uint256).max);
File: contracts/strategies/ConvexStrategyBase.sol #21 108 _CVX.safeApprove(address(_strategySwapper), type(uint256).max);
File: contracts/strategies/ConvexStrategyBase.sol #22 109 _WETH.safeApprove(address(_strategySwapper), type(uint256).max);
File: contracts/strategies/ConvexStrategyBase.sol #23 279 IERC20(token_).safeApprove(address(_strategySwapper), 0);
File: contracts/strategies/ConvexStrategyBase.sol #24 280 IERC20(token_).safeApprove(address(_strategySwapper), type(uint256).max);
File: contracts/strategies/StrategySwapper.sol #25 209 IERC20(token_).safeApprove(spender_, type(uint256).max);
File: contracts/vault/Erc20Vault.sol #26 21 IERC20(underlying_).safeApprove(address(reserve), type(uint256).max);
File: contracts/vault/Erc20Vault.sol #27 22 IERC20(underlying_).safeApprove(_pool, type(uint256).max);
address(0x0)
when assigning values to address
state variablesFile: contracts/actions/topup/TopUpActionFeeHandler.sol #1 55 actionContract = _actionContract;
File: contracts/CvxCrvRewardsLocker.sol #2 151 treasury = _treasury;
File: contracts/StakerVault.sol #3 66 token = _token;
File: contracts/strategies/ConvexStrategyBase.sol #4 100 vault = vault_;
File: contracts/strategies/ConvexStrategyBase.sol #5 101 _strategist = strategist_;
File: contracts/strategies/ConvexStrategyBase.sol #6 182 communityReserve = _communityReserve;
File: contracts/strategies/ConvexStrategyBase.sol #7 261 _strategist = strategist_;
abi.encodePacked()
should not be used with dynamic types when passing the result to a hash function such as keccak256()
Use abi.encode()
instead which will pad items to 32 bytes, which will prevent hash collisions (e.g. abi.encodePacked(0x123,0x456)
=> 0x123456
=> abi.encodePacked(0x1,0x23456)
, but abi.encode(0x123,0x456)
=> 0x0...1230...456
). "Unless there is a compelling reason, abi.encode
should be preferred". If there is only one argument to abi.encodePacked()
it can often be cast to bytes()
or bytes32()
instead.
File: contracts/actions/topup/handlers/CTokenRegistry.sol #1 67 keccak256(abi.encodePacked(ctoken.symbol())) == keccak256(abi.encodePacked("cETH"))
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment
File: contracts/actions/topup/TopUpAction.sol #1 713 // TODO: add constant gas consumed for transfer and tx prologue
File: contracts/strategies/ConvexStrategyBase.sol #2 4 // TODO Add validation of curve pools
File: contracts/strategies/ConvexStrategyBase.sol #3 5 // TODO Test validation
address.call{value:x}()
should be used instead of payable.transfer()
The use of payable.transfer()
is heavily frowned upon because it can lead to the locking of funds. The transfer()
call requires that the recipient has a payable
callback, only provides 2300 gas for its operation. This means the following cases can cause the transfer to fail:
payable
callbackpayable
callback spends more than 2300 gas (which is only enough to emit something)File: backd/contracts/vault/VaultReserve.sol #1 81 payable(msg.sender).transfer(amount);
uses the onlyVault
modifier, and vaults currently have empty payable
callbacks, so they don't currently revert
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/VaultReserve.sol#L81
File: backd/contracts/vault/EthVault.sol #2 29 payable(to).transfer(amount);
uses the onlyPoolOrGovernance
modifier, and pools currently have an empty payable
callback, so they don't currently rever. Governance is currently deployed and not seeing issues, so presumably it also has an empty payable
callback
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/EthVault.sol#L29
File: backd/contracts/vault/EthVault.sol #3 37 payable(addressProvider.getTreasury()).transfer(amount);
the treasury is currently deployed and not seeing issues, so presumably it also has an empty payable
callback
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/EthVault.sol#L37
File: backd/contracts/strategies/BkdEthCvx.sol #4 77 payable(vault).transfer(amount);
vaults currently have an empty payable
callback
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/strategies/BkdEthCvx.sol#L77
File: backd/contracts/strategies/BkdEthCvx.sol #5 93 payable(vault).transfer(amount);
vaults currently have an empty payable
callback
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/strategies/BkdEthCvx.sol#L93
File: backd/contracts/strategies/BkdEthCvx.sol #6 117 payable(vault).transfer(underlyingBalance);
vaults currently have an empty payable
callback
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/strategies/BkdEthCvx.sol#L117
__gap[50]
storage variable to allow for new storage variables in later versionsSee this link for a description of this storage variable. While some contracts may not currently be sub-classed, adding the variable now protects against forgetting to add it in the future.
File: contracts/LpToken.sol #1 10 contract LpToken is ILpToken, ERC20Upgradeable {
In the example below, a + b
may overflow even though the division that comes later would prevent it. This particular case can be prevented by doing (a & b) + (a ^ b) / b
. There are other functions with similar issues. See this library for ways of doing math without this sort of issue.
File: backd/libraries/ScaledMath.sol #1 40 function divRoundUp(uint256 a, uint256 b) internal pure returns (uint256) { 41 return (a + b - 1) / b; 42 }
payable
function does not reject payments to ERC20 tokensFile: backd/contracts/vault/VaultReserve.sol #1 50 if (token == address(0)) { 51 require(msg.value == amount, Error.INVALID_AMOUNT); 52 _balances[msg.sender][token] += msg.value; 53 return true; 54 } 55 uint256 balance = IERC20(token).balanceOf(address(this));
After the if-statement there should be a require(0 == msg.value)
to ensure no Ether is being used when updating ERC20 balances. This is non-critical since the function has the onlyVault
modifier, and presumably vaults would be coded never to deposit Ether to ERC20 tokens
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/VaultReserve.sol#L50-L55
return
statement when the function defines a named return variable, is redundantFile: contracts/pool/PoolFactory.sol #1 216 return addrs;
public
functions not called by the contract should be declared external
insteadContracts are allowed to override their parents' functions and change the visibility from external
to public
.
File: contracts/actions/topup/TopUpAction.sol #1 742 function prepareTopUpHandler(bytes32 protocol, address newHandler) 743 public 744 onlyGovernance 745 returns (bool)
File: contracts/CvxCrvRewardsLocker.sol #2 222 function withdraw(address token, uint256 amount) public onlyGovernance returns (bool) {
constant
s should be defined rather than using magic numbersFile: contracts/oracles/ChainlinkOracleProvider.sol #1 47 return (getPriceUSD(asset) * 1e18) / getPriceUSD(address(0));
File: contracts/oracles/ChainlinkUsdWrapper.sol #2 56 return (roundId_, (answer_ * _ethPrice()) / 1e8, startedAt_, updatedAt_, answeredInRound_);
File: contracts/pool/LiquidityPool.sol #3 208 require(newRatio <= (ScaledMath.DECIMAL_SCALE * 50) / 100, Error.INVALID_AMOUNT);
File: contracts/pool/LiquidityPool.sol #4 208 require(newRatio <= (ScaledMath.DECIMAL_SCALE * 50) / 100, Error.INVALID_AMOUNT);
File: contracts/pool/PoolFactory.sol #5 184 require(lpTokenArgs.decimals == 18, Error.INVALID_DECIMALS);
File: contracts/strategies/BkdEthCvx.sol #6 38 imbalanceToleranceIn = 0.0007e18;
File: contracts/strategies/BkdEthCvx.sol #7 39 imbalanceToleranceOut = 0.0104e18;
File: contracts/strategies/BkdTriHopCvx.sol #8 59 decimalMultiplier = 10**(18 - IERC20Full(underlying_).decimals());
File: contracts/strategies/BkdTriHopCvx.sol #9 65 imbalanceToleranceIn = 0.001e18;
File: contracts/strategies/BkdTriHopCvx.sol #10 66 imbalanceToleranceOut = 0.048e18;
File: contracts/strategies/BkdTriHopCvx.sol #11 67 hopImbalanceToleranceIn = 0.001e18;
File: contracts/strategies/BkdTriHopCvx.sol #12 68 hopImbalanceToleranceOut = 0.0015e18;
File: contracts/strategies/BkdTriHopCvx.sol #13 152 uint256[3] memory hopAmounts;
File: contracts/strategies/BkdTriHopCvx.sol #14 196 uint256[3] memory hopAmounts;
File: contracts/strategies/StrategySwapper.sol #15 111 require(slippageTolerance_ > 0.8e18, Error.INVALID_SLIPPAGE_TOLERANCE);
File: contracts/strategies/StrategySwapper.sol #16 288 return 10**(18 - IERC20Full(token_).decimals());
1e6
) rather than decimal literals (e.g. 1000000
), for readabilityFile: contracts/utils/CvxMintAmount.sol #1 7 uint256 private constant _CLIFF_SIZE = 100000 * 1e18; //new cliff every 100,000 tokens
File: contracts/utils/CvxMintAmount.sol #2 9 uint256 private constant _MAX_SUPPLY = 100000000 * 1e18; //100 mil max supply
Use a solidity version of at least 0.8.12 to get string.concat()
to be used instead of abi.encodePacked(,)
File: contracts/actions/topup/handlers/CTokenRegistry.sol #1 2 pragma solidity 0.8.9;
File: contracts/actions/topup/TopUpActionFeeHandler.sol #2 2 pragma solidity 0.8.9;
File: contracts/actions/topup/TopUpAction.sol #3 2 pragma solidity 0.8.9;
Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant
in a library
. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync.
File: contracts/actions/topup/handlers/CTokenRegistry.sol #1 9 Comptroller public immutable comptroller;
seen in contracts/actions/topup/handlers/CompoundHandler.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/CTokenRegistry.sol#L9
File: contracts/actions/topup/TopUpAction.sol #2 157 IAddressProvider public immutable addressProvider;
seen in contracts/access/RoleManager.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L157
File: contracts/actions/topup/TopUpAction.sol #3 156 IController public immutable controller;
seen in contracts/actions/topup/TopUpActionFeeHandler.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L156
File: contracts/Controller.sol #4 19 IAddressProvider public immutable override addressProvider;
seen in contracts/actions/topup/TopUpAction.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/Controller.sol#L19
File: contracts/GasBank.sol #5 9 IController public immutable controller;
seen in contracts/actions/topup/TopUpAction.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/GasBank.sol#L9
File: contracts/GasBank.sol #6 10 IAddressProvider public immutable addressProvider;
seen in contracts/Controller.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/GasBank.sol#L10
File: contracts/pool/LiquidityPool.sol #7 65 IController public immutable controller;
seen in contracts/GasBank.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/LiquidityPool.sol#L65
File: contracts/pool/LiquidityPool.sol #8 66 IAddressProvider public immutable addressProvider;
seen in contracts/GasBank.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/LiquidityPool.sol#L66
File: contracts/pool/PoolFactory.sol #9 64 IController public immutable controller;
seen in contracts/pool/LiquidityPool.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L64
File: contracts/pool/PoolFactory.sol #10 65 IAddressProvider public immutable addressProvider;
seen in contracts/pool/LiquidityPool.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L65
File: contracts/StakerVault.sol #11 43 IController public immutable controller;
seen in contracts/pool/PoolFactory.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/StakerVault.sol#L43
File: contracts/vault/Vault.sol #12 48 IController public immutable controller;
seen in contracts/StakerVault.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/Vault.sol#L48
File: contracts/vault/Vault.sol #13 49 IAddressProvider public immutable addressProvider;
seen in contracts/pool/PoolFactory.sol https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/Vault.sol#L49
Some lines use // x
and some use //x
. The instances below point out the usages that don't follow the majority, within each file
File: contracts/utils/CvxMintAmount.sol #1 8 uint256 private constant _CLIFF_COUNT = 1000; // 1,000 cliffs
File: contracts/utils/CvxMintAmount.sol #2 11 IERC20(address(0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B)); // CVX Token
File: contracts/actions/topup/handlers/CompoundHandler.sol #1 85 * @notice Returns the collaterization ratio of the user.
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 86 * A result of 1.5 (x1e18) means that the user has a 150% collaterization ratio.
File: contracts/actions/topup/handlers/CompoundHandler.sol #3 103 * @return The amount of debt that was repayed in the underlying.
File: contracts/actions/topup/TopUpActionFeeHandler.sol #4 157 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/actions/topup/TopUpActionFeeHandler.sol #5 202 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/actions/topup/TopUpAction.sol #6 396 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/actions/topup/TopUpAction.sol #7 737 * @dev Setting the addres to 0 means that the protocol will no longer be supported.
File: contracts/actions/topup/TopUpAction.sol #8 859 * If this is greater than `requiredAmount` more tokens will be locked.
requiredAmount - no such variable https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L859
File: contracts/actions/topup/TopUpKeeperHelper.sol #9 156 * @param length The length to trucate the list of topups to.
File: contracts/AddressProvider.sol #10 297 * @dev Does not revert if the pool deos not exist
File: contracts/AddressProvider.sol #11 308 * @dev Reverts if the pool deos not exist
File: contracts/CvxCrvRewardsLocker.sol #12 131 * @notice Processes exipred locks.
File: contracts/CvxCrvRewardsLocker.sol #13 254 // Swap CRV for cxvCRV and stake
cxvCRV - should be cvxCRV https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/CvxCrvRewardsLocker.sol#L254
File: contracts/LpToken.sol #14 62 * @return Aamount of tokens burned.
File: contracts/LpToken.sol #15 79 * @dev We notify that LP tokens have been transfered
File: contracts/pool/LiquidityPool.sol #16 185 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/pool/LiquidityPool.sol #17 214 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/pool/LiquidityPool.sol #18 243 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/pool/LiquidityPool.sol #19 272 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/pool/LiquidityPool.sol #20 304 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/pool/LiquidityPool.sol #21 352 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/pool/LiquidityPool.sol #22 644 * @notice Retuns if the pool has an active deposit limit
File: contracts/pool/LiquidityPool.sol #23 804 * @dev Overriden for testing
File: contracts/strategies/BkdEthCvx.sol #24 136 * @param _underlyingAmount Amount of underlying that is being widthdrawn from Curve Pool.
File: contracts/strategies/BkdEthCvx.sol #25 154 * @dev Uses get_virtual_price which is less suceptible to manipulation.
File: contracts/strategies/BkdEthCvx.sol #26 165 * @dev Uses get_virtual_price which is less suceptible to manipulation.
File: contracts/strategies/BkdTriHopCvx.sol #27 27 event SetHopImbalanceToleranceIn(uint256 value); // Emitted after a succuessful setting of hop imbalance tolerance in
File: contracts/strategies/BkdTriHopCvx.sol #28 28 event SetHopImbalanceToleranceOut(uint256 value); // Emitted after a succuessful setting of hop imbalance tolerance out
File: contracts/strategies/BkdTriHopCvx.sol #29 79 * @param _hopImbalanceToleranceIn New hop imbalance tolarance in.
File: contracts/strategies/BkdTriHopCvx.sol #30 95 * @param _hopImbalanceToleranceOut New hop imbalance tolarance out.
File: contracts/strategies/BkdTriHopCvx.sol #31 248 * @param _hopLpAmount Amount of Hop LP that is being widthdrawn from Curve Pool.
File: contracts/strategies/BkdTriHopCvx.sol #32 258 * @return The mininum Hop LP balance to accept.
File: contracts/strategies/BkdTriHopCvx.sol #33 282 * @param _underlyingAmount Amount of underlying that is being widthdrawn from Curve Hop Pool.
File: contracts/strategies/BkdTriHopCvx.sol #34 295 * @return The mininum underlying balance to accept.
File: contracts/strategies/BkdTriHopCvx.sol #35 304 * @dev Uses get_virtual_price which is less suceptible to manipulation.
File: contracts/strategies/BkdTriHopCvx.sol #36 315 * @dev Uses get_virtual_price which is less suceptible to manipulation.
File: contracts/strategies/BkdTriHopCvx.sol #37 326 * @dev Uses get_virtual_price which is less suceptible to manipulation.
File: contracts/strategies/BkdTriHopCvx.sol #38 340 * @dev Uses get_virtual_price which is less suceptible to manipulation.
File: contracts/strategies/ConvexStrategyBase.sol #39 61 event Deposit(); // Emitted after a successfull deposit
File: contracts/strategies/ConvexStrategyBase.sol #40 63 event WithdrawAll(uint256 amount); // Emitted after successfully withdrwaing all
File: contracts/strategies/ConvexStrategyBase.sol #41 65 event SetCommunityReserve(address reserve); // Emitted after a succuessful setting of reserve
File: contracts/strategies/ConvexStrategyBase.sol #42 66 event SetCrvCommunityReserveShare(uint256 value); // Emitted after a succuessful setting of CRV Community Reserve Share
File: contracts/strategies/ConvexStrategyBase.sol #43 67 event SetCvxCommunityReserveShare(uint256 value); // Emitted after a succuessful setting of CVX Community Reserve Share
File: contracts/strategies/ConvexStrategyBase.sol #44 68 event SetImbalanceToleranceIn(uint256 value); // Emitted after a succuessful setting of imbalance tolerance in
File: contracts/strategies/ConvexStrategyBase.sol #45 69 event SetImbalanceToleranceOut(uint256 value); // Emitted after a succuessful setting of imbalance tolerance out
File: contracts/strategies/ConvexStrategyBase.sol #46 70 event SetStrategist(address strategist); // Emitted after a succuessful setting of strategist
File: contracts/strategies/ConvexStrategyBase.sol #47 175 * @notice Set the address of the communit reserve.
File: contracts/strategies/ConvexStrategyBase.sol #48 224 * @param imbalanceToleranceIn_ New imbalance tolarance in.
File: contracts/strategies/ConvexStrategyBase.sol #49 240 * @param imbalanceToleranceOut_ New imbalance tolarance out.
File: contracts/strategies/StrategySwapper.sol #50 34 event SetSlippageTolerance(uint256 value); // Emitted after a succuessful setting of slippage tolerance
File: contracts/strategies/StrategySwapper.sol #51 35 event SetCurvePool(address token, address curvePool); // Emitted after a succuessful setting of a Curve Pool
File: contracts/strategies/StrategySwapper.sol #52 36 event SetSwapViaUniswap(address token, bool swapViaUniswap); // Emitted after a succuessful setting of swap via Uniswap
File: contracts/strategies/StrategySwapper.sol #53 292 * @dev Returns the Curve Pool coin indicies for a given Token.
File: contracts/strategies/StrategySwapper.sol #54 293 * @param curvePool_ The Curve Pool to return the indicies for.
File: contracts/strategies/StrategySwapper.sol #55 294 * @param token_ The Token to get the indicies for.
File: contracts/strategies/StrategySwapper.sol #56 307 * @dev Returns the minimum amount of Token to recieve from swap.
File: contracts/strategies/StrategySwapper.sol #57 310 * @return minAmountOut The minimum amount of Token to recieve from swap.
File: contracts/strategies/StrategySwapper.sol #58 324 * @dev Returns the minimum amount of WETH to recieve from swap.
File: contracts/strategies/StrategySwapper.sol #59 327 * @return minAmountOut The minimum amount of WETH to recieve from swap.
File: contracts/utils/Preparable.sol #60 10 * callers should make sure to have the proper checks in palce
File: contracts/utils/Preparable.sol #61 34 * @notice Prepares an uint256 that should be commited to the contract
File: contracts/utils/Preparable.sol #62 58 * @notice Prepares an address that should be commited to the contract
File: contracts/vault/Vault.sol #63 218 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/vault/Vault.sol #64 270 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/vault/Vault.sol #65 293 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/vault/Vault.sol #66 317 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/vault/Vault.sol #67 348 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/vault/Vault.sol #68 373 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/vault/Vault.sol #69 398 * @dev Needs to be called after the update was prepraed. Fails if called before time delay is met.
File: contracts/access/Authorization.sol (various lines) #1
File: contracts/access/RoleManager.sol (various lines) #2
File: contracts/oracles/ChainlinkUsdWrapper.sol (various lines) #3
File: contracts/oracles/OracleProviderExtensions.sol (various lines) #4
File: contracts/pool/Erc20Pool.sol (various lines) #5
File: contracts/pool/EthPool.sol (various lines) #6
File: contracts/utils/CvxMintAmount.sol (various lines) #7
File: contracts/vault/Erc20Vault.sol (various lines) #8
File: contracts/vault/EthVault.sol (various lines) #9
File: libraries/AddressProviderMeta.sol (various lines) #10
File: libraries/Errors.sol (various lines) #11
File: contracts/actions/topup/handlers/AaveHandler.sol #1 29 /** 30 * @notice Executes the top-up of a position. 31 * @param account Account holding the position. 32 * @param underlying Underlying for tup-up. 33 * @param amount Amount to top-up by. 34 * @return `true` if successful. 35 */ 36 function topUp( 37 bytes32 account, 38 address underlying, 39 uint256 amount, 40 bytes memory extra 41 ) external override returns (bool) {
Missing: @param extra
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/AaveHandler.sol#L29-L41
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 43 /** 44 * @notice Executes the top-up of a position. 45 * @param account Account holding the position. 46 * @param underlying Underlying for tup-up. 47 * @param amount Amount to top-up by. 48 * @return `true` if successful. 49 */ 50 function topUp( 51 bytes32 account, 52 address underlying, 53 uint256 amount, 54 bytes memory extra 55 ) external override returns (bool) {
Missing: @param extra
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/CompoundHandler.sol#L43-L55
File: contracts/actions/topup/handlers/CompoundHandler.sol #3 84 /** 85 * @notice Returns the collaterization ratio of the user. 86 * A result of 1.5 (x1e18) means that the user has a 150% collaterization ratio. 87 * @param account account for which to check the factor. 88 * @return User factor. 89 */ 90 function getUserFactor(bytes32 account, bytes memory) external view override returns (uint256) {
Missing: @param null
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/CompoundHandler.sol#L84-L90
File: contracts/actions/topup/handlers/CompoundHandler.sol #4 98 /** 99 * @notice Repays any existing debt for the given underlying. 100 * @param account Account for which to repay the debt. 101 * @param underlying The underlying token to repay the debt for. 102 * @param maximum The maximum amount of debt to repay. 103 * @return The amount of debt that was repayed in the underlying. 104 */ 105 function _repayAnyDebt( 106 address account, 107 address underlying, 108 uint256 maximum, 109 CToken ctoken 110 ) internal returns (uint256) {
Missing: @param ctoken
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/handlers/CompoundHandler.sol#L98-L110
File: contracts/actions/topup/TopUpAction.sol #5 201 * @param record containing the data for the position to register 202 */ 203 function register( 204 bytes32 account, 205 bytes32 protocol, 206 uint128 depositAmount, 207 Record memory record 208 ) external payable returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L201-L208
File: contracts/actions/topup/TopUpAction.sol #6 440 * @param token Address of deposit token that can be used by the action. 441 */ 442 function addUsableToken(address token) external override onlyGovernance returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L440-L442
File: contracts/actions/topup/TopUpAction.sol #7 802 * @param protocol Protocol where the position is held. 803 */ 804 function getPosition( 805 address payer, 806 bytes32 account, 807 bytes32 protocol 808 ) public view override returns (Record memory) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/actions/topup/TopUpAction.sol#L802-L808
File: contracts/AddressProvider.sol #8 77 * @param action Address of action to add. 78 */ 79 function addAction(address action) external onlyGovernance returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/AddressProvider.sol#L77-L79
File: contracts/AddressProvider.sol #9 196 /** 197 * @notice Initializes an address 198 * @param key Key to initialize 199 * @param initialAddress Address for `key` 200 */ 201 function initializeAddress( 202 bytes32 key, 203 address initialAddress, 204 bool freezable 205 ) public override onlyGovernance {
Missing: @param freezable
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/AddressProvider.sol#L196-L205
File: contracts/AddressProvider.sol #10 253 /** 254 * @notice Execute update of `key` 255 * @return New address. 256 */ 257 function executeAddress(bytes32 key) external override returns (address) {
Missing: @param key
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/AddressProvider.sol#L253-L257
File: contracts/AddressProvider.sol #11 263 /** 264 * @notice Reset `key` 265 * @return true if it was reset 266 */ 267 function resetAddress(bytes32 key) external onlyGovernance returns (bool) {
Missing: @param key
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/AddressProvider.sol#L263-L267
File: contracts/AddressProvider.sol #12 385 /** 386 * @notice Tries to get the staker vault for a given token but does not throw if it does not exist 387 * @return A boolean set to true if the vault exists and the vault address. 388 */ 389 function tryGetStakerVault(address token) external view override returns (bool, address) {
Missing: @param token
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/AddressProvider.sol#L385-L389
File: contracts/Controller.sol #13 108 /** 109 * @return the total amount of ETH require by `payer` to cover the fees for 110 * positions registered in all actions 111 */ 112 function getTotalEthRequiredForGas(address payer) external view override returns (uint256) {
Missing: @param payer
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/Controller.sol#L108-L112
File: contracts/CvxCrvRewardsLocker.sol #14 80 * @param _spendRatio New spend ratio to be used. 81 */ 82 function setSpendRatio(uint256 _spendRatio) external onlyGovernance returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/CvxCrvRewardsLocker.sol#L80-L82
File: contracts/CvxCrvRewardsLocker.sol #15 95 * @param lockAndStake If true, claimed reward tokens (CRV) will be locked and staked (CRV for cvxCRV and CVX for vlCVX). 96 */ 97 function claimRewards(bool lockAndStake) external override returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/CvxCrvRewardsLocker.sol#L95-L97
File: contracts/CvxCrvRewardsLocker.sol #16 158 * @param token Token to withdraw entire balance of. 159 */ 160 function withdraw(address token) external onlyGovernance returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/CvxCrvRewardsLocker.sol#L158-L160
File: contracts/CvxCrvRewardsLocker.sol #17 220 * @param amount Amount of token to withdraw. 221 */ 222 function withdraw(address token, uint256 amount) public onlyGovernance returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/CvxCrvRewardsLocker.sol#L220-L222
File: contracts/GasBank.sol #18 52 /** 53 * @return the balance of `account` 54 */ 55 function balanceOf(address account) external view override returns (uint256) {
Missing: @param account
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/GasBank.sol#L52-L55
File: contracts/pool/PoolFactory.sol #19 88 * @param implementation of pool implementation to add. 89 */ 90 function addPoolImplementation(bytes32 name, address implementation) 91 external 92 onlyGovernance 93 returns (bool)
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L88-L93
File: contracts/pool/PoolFactory.sol #20 101 * @param implementation of lp token implementation to add. 102 */ 103 function addLpTokenImplementation(bytes32 name, address implementation) 104 external 105 onlyGovernance 106 returns (bool)
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L101-L106
File: contracts/pool/PoolFactory.sol #21 114 * @param implementation of vault implementation to add. 115 */ 116 function addVaultImplementation(bytes32 name, address implementation) 117 external 118 onlyGovernance 119 returns (bool)
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L114-L119
File: contracts/pool/PoolFactory.sol #22 127 * @param implementation of staker vault implementation to add. 128 */ 129 function addStakerVaultImplementation(bytes32 name, address implementation) 130 external 131 onlyGovernance 132 returns (bool)
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L127-L132
File: contracts/pool/PoolFactory.sol #23 137 /** 138 * @notice Deploys a new pool and LP token. 139 * @dev Decimals is an argument as not all ERC20 tokens implement the ERC20Detailed interface. 140 * An implementation where `getUnderlying()` returns the zero address is for ETH pools. 141 * @param poolName Name of the pool. 142 * @param underlying Address of the pool's underlying. 143 * @param lpTokenArgs Arguments to create the LP token for the pool 144 * @param vaultArgs Arguments to create the vault 145 * @param implementationNames Name of the implementations to use 146 * @return addrs Address of the deployed pool, address of the pool's deployed LP token. 147 */ 148 function deployPool( 149 string calldata poolName, 150 uint256 depositCap, 151 address underlying, 152 LpTokenArgs calldata lpTokenArgs, 153 VaultArgs calldata vaultArgs, 154 ImplementationNames calldata implementationNames 155 ) external onlyGovernance returns (Addresses memory addrs) {
Missing: @param depositCap
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L137-L155
File: contracts/pool/PoolFactory.sol #24 223 * @param implementation of lp token implementation to add. 224 */ 225 function _addImplementation( 226 bytes32 key, 227 bytes32 name, 228 address implementation 229 ) internal returns (bool) {
Missing: @return
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/pool/PoolFactory.sol#L223-L229
File: contracts/StakerVault.sol #25 87 /** 88 * @notice Registers an address as a strategy to be excluded from token accumulation. 89 * @dev This should be used is a strategy deposits into a stakerVault and should not get gov. tokens. 90 * @return `true` if success. 91 */ 92 function addStrategy(address strategy) external override returns (bool) {
Missing: @param strategy
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/StakerVault.sol#L87-L92
File: contracts/utils/Preparable.sol #26 33 /** 34 * @notice Prepares an uint256 that should be commited to the contract 35 * after `_MIN_DELAY` elapsed 36 * @param value The value to prepare 37 * @return `true` if success. 38 */ 39 function _prepare( 40 bytes32 key, 41 uint256 value, 42 uint256 delay 43 ) internal returns (bool) {
Missing: @param key
@param delay
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/utils/Preparable.sol#L33-L43
File: contracts/utils/Preparable.sol #27 57 /** 58 * @notice Prepares an address that should be commited to the contract 59 * after `_MIN_DELAY` elapsed 60 * @param value The value to prepare 61 * @return `true` if success. 62 */ 63 function _prepare( 64 bytes32 key, 65 address value, 66 uint256 delay 67 ) internal returns (bool) {
Missing: @param key
@param delay
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/utils/Preparable.sol#L57-L67
File: contracts/utils/Preparable.sol #28 81 /** 82 * @notice Reset a uint256 key 83 * @return `true` if success. 84 */ 85 function _resetUInt256Config(bytes32 key) internal returns (bool) {
Missing: @param key
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/utils/Preparable.sol#L81-L85
File: contracts/utils/Preparable.sol #29 93 /** 94 * @notice Reset an address key 95 * @return `true` if success. 96 */ 97 function _resetAddressConfig(bytes32 key) internal returns (bool) {
Missing: @param key
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/utils/Preparable.sol#L93-L97
File: contracts/utils/Preparable.sol #30 115 /** 116 * @notice Execute uint256 config update (with time delay enforced). 117 * @dev Needs to be called after the update was prepared. Fails if called before time delay is met. 118 * @return New value. 119 */ 120 function _executeUInt256(bytes32 key) internal returns (uint256) {
Missing: @param key
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/utils/Preparable.sol#L115-L120
File: contracts/utils/Preparable.sol #31 127 /** 128 * @notice Execute address config update (with time delay enforced). 129 * @dev Needs to be called after the update was prepared. Fails if called before time delay is met. 130 * @return New value. 131 */ 132 function _executeAddress(bytes32 key) internal returns (address) {
Missing: @param key
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/utils/Preparable.sol#L127-L132
File: libraries/AddressProviderHelpers.sol #32 15 /** 16 * @return The address of the treasury. 17 */ 18 function getTreasury(IAddressProvider provider) internal view returns (address) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L15-L18
File: libraries/AddressProviderHelpers.sol #33 22 /** 23 * @return The gas bank. 24 */ 25 function getGasBank(IAddressProvider provider) internal view returns (IGasBank) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L22-L25
File: libraries/AddressProviderHelpers.sol #34 29 /** 30 * @return The address of the vault reserve. 31 */ 32 function getVaultReserve(IAddressProvider provider) internal view returns (IVaultReserve) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L29-L32
File: libraries/AddressProviderHelpers.sol #35 36 /** 37 * @return The address of the swapperRegistry. 38 */ 39 function getSwapperRegistry(IAddressProvider provider) internal view returns (address) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L36-L39
File: libraries/AddressProviderHelpers.sol #36 43 /** 44 * @return The oracleProvider. 45 */ 46 function getOracleProvider(IAddressProvider provider) internal view returns (IOracleProvider) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L43-L46
File: libraries/AddressProviderHelpers.sol #37 50 /** 51 * @return the address of the BKD locker 52 */ 53 function getBKDLocker(IAddressProvider provider) internal view returns (address) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L50-L53
File: libraries/AddressProviderHelpers.sol #38 57 /** 58 * @return the address of the BKD locker 59 */ 60 function getRoleManager(IAddressProvider provider) internal view returns (IRoleManager) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L57-L60
File: libraries/AddressProviderHelpers.sol #39 64 /** 65 * @return the controller 66 */ 67 function getController(IAddressProvider provider) internal view returns (IController) {
Missing: @param provider
https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/libraries/AddressProviderHelpers.sol#L64-L67
indexed
fieldsEach event
should use three indexed
fields if there are three or more fields
File: contracts/actions/topup/TopUpActionFeeHandler.sol #1 37 event KeeperFeesClaimed(address indexed keeper, address token, uint256 totalClaimed);
File: contracts/actions/topup/TopUpActionFeeHandler.sol #2 39 event FeesPayed( 40 address indexed payer, 41 address indexed keeper, 42 address token, 43 uint256 amount, 44 uint256 keeperAmount, 45 uint256 lpAmount 46 );
File: contracts/CvxCrvRewardsLocker.sol #3 46 event NewSpendRatio(uint256 newSpendRatio);
File: contracts/CvxCrvRewardsLocker.sol #4 47 event NewTreasury(address newTreasury);
File: contracts/pool/PoolFactory.sol #5 75 event NewPool(address pool, address vault, address lpToken, address stakerVault);
File: contracts/pool/PoolFactory.sol #6 76 event NewImplementation(bytes32 key, bytes32 name, address implementation);
File: contracts/strategies/BkdTriHopCvx.sol #7 27 event SetHopImbalanceToleranceIn(uint256 value); // Emitted after a succuessful setting of hop imbalance tolerance in
File: contracts/strategies/BkdTriHopCvx.sol #8 28 event SetHopImbalanceToleranceOut(uint256 value); // Emitted after a succuessful setting of hop imbalance tolerance out
File: contracts/strategies/ConvexStrategyBase.sol #9 62 event Withdraw(uint256 amount); // Emitted after a successful withdrawal
File: contracts/strategies/ConvexStrategyBase.sol #10 63 event WithdrawAll(uint256 amount); // Emitted after successfully withdrwaing all
File: contracts/strategies/ConvexStrategyBase.sol #11 65 event SetCommunityReserve(address reserve); // Emitted after a succuessful setting of reserve
File: contracts/strategies/ConvexStrategyBase.sol #12 66 event SetCrvCommunityReserveShare(uint256 value); // Emitted after a succuessful setting of CRV Community Reserve Share
File: contracts/strategies/ConvexStrategyBase.sol #13 67 event SetCvxCommunityReserveShare(uint256 value); // Emitted after a succuessful setting of CVX Community Reserve Share
File: contracts/strategies/ConvexStrategyBase.sol #14 68 event SetImbalanceToleranceIn(uint256 value); // Emitted after a succuessful setting of imbalance tolerance in
File: contracts/strategies/ConvexStrategyBase.sol #15 69 event SetImbalanceToleranceOut(uint256 value); // Emitted after a succuessful setting of imbalance tolerance out
File: contracts/strategies/ConvexStrategyBase.sol #16 70 event SetStrategist(address strategist); // Emitted after a succuessful setting of strategist
File: contracts/strategies/ConvexStrategyBase.sol #17 71 event AddRewardToken(address token); // Emitted after successfully adding a new reward token
File: contracts/strategies/ConvexStrategyBase.sol #18 72 event RemoveRewardToken(address token); // Emitted after successfully removing a reward token
File: contracts/strategies/ConvexStrategyBase.sol #19 73 event Harvest(uint256 amount); // Emitted after a successful harvest
File: contracts/strategies/StrategySwapper.sol #20 34 event SetSlippageTolerance(uint256 value); // Emitted after a succuessful setting of slippage tolerance
File: contracts/strategies/StrategySwapper.sol #21 35 event SetCurvePool(address token, address curvePool); // Emitted after a succuessful setting of a Curve Pool
File: contracts/strategies/StrategySwapper.sol #22 36 event SetSwapViaUniswap(address token, bool swapViaUniswap); // Emitted after a succuessful setting of swap via Uniswap
#0 - liveactionllama
2022-04-28T00:50:19Z
Warden created this issue as a placeholder, because their submission was too large for the contest form. They then emailed their md file to our team and we received at 22:47 UTC on 04/27/2022 (prior to contest close). I've updated this issue with their md file content.
#1 - chase-manning
2022-04-28T10:10:59Z
I consider this report to be of particularly high quality
#2 - liveactionllama
2022-05-06T22:24:14Z
Note: my original copy/paste did not capture all of the warden's content. I've updated this issue to now contain the entirety from the original submission. I've also notified the sponsor and judge.
#3 - gzeoneth
2022-05-08T20:03:00Z
NIce submission, warden covered basically all the low risk and non-critical issues. Would be nice if there is an index.
AaveHandler
does not extend BaseHandler
receive()
function will lock Ether in contract_prepareDeadline()
, _setConfig()
, and _executeDeadline()
should be private
Should be non-criticalsafeApprove()
is deprecatedaddress(0x0)
when assigning values to address
state variablesabi.encodePacked()
should not be used with dynamic types when passing the result to a hash function such as keccak256()
address.call{value:x}()
should be used instead of payable.transfer()
__gap[50]
storage variable to allow for new storage variables in later versionspayable
function does not reject payments to ERC20 tokensreturn
statement when the function defines a named return variable, is redundantpublic
functions not called by the contract should be declared external
insteadconstant
s should be defined rather than using magic numbers1e6
) rather than decimal literals (e.g. 1000000
), for readabilityindexed
fields🌟 Selected for report: joestakey
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xkatana, 0xmint, Dravee, Funen, IllIllI, MaratCerby, NoamYakov, Tadashi, TerrierLover, Tomio, WatchPug, catchup, defsec, fatherOfBlocks, hake, horsefacts, kenta, oyc_109, pauliax, rayn, rfa, robee, saian, securerodd, simon135, slywaters, sorrynotsorry, tin537, z3s
337.9588 USDC - $337.96
Vulnerability details:
address
mappings can be combined into a single mapping
of an address
to a struct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas). Reads and subsequent writes can also be cheaper
File: contracts/actions/topup/TopUpAction.sol #1 162 mapping(address => mapping(bytes32 => mapping(bytes32 => Record))) private _positions; 163 164 mapping(address => RecordMeta[]) internal _userPositions;
File: contracts/StakerVault.sol #2 47 mapping(address => uint256) public balances; 48 mapping(address => uint256) public actionLockedBalances; 49 50 mapping(address => mapping(address => uint256)) internal _allowances;
File: contracts/strategies/StrategySwapper.sol #3 31 mapping(address => ICurveSwapEth) public curvePools; // Curve Pool to use for swaps to ETH (if any) 32 mapping(address => bool) public swapViaUniswap; // If Uniswap should be used over Sushiswap for swaps
File: contracts/vault/VaultReserve.sol #4 22 mapping(address => mapping(address => uint256)) private _balances; 23 mapping(address => uint256) private _lastWithdrawal;
immutable
Avoids a Gsset (20000 gas)
File: contracts/strategies/BkdTriHopCvx.sol #1 25 uint256 public decimalMultiplier; // Used for converting between underlying and LP
File: contracts/vault/VaultReserve.sol #2 25 uint256 public minWithdrawalDelay;
There currently is no setter function for this variable https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/VaultReserve.sol#L25
If variables occupying the same slot are both written the same function or by the constructor, avoids a separate Gsset (20000 gas). Reads of the variables can also be cheaper
File: contracts/vault/VaultStorage.sol #1 9 uint256 public currentAllocated;
Variable ordering with one fewer slots: uint256(32):currentAllocated, uint256(32):waitingForRemovalAllocated, uint256(32):totalDebt, address(20):pool, bool(1):strategyActive, user-defined(*):_strategiesWaitingForRemoval https://github.com/code-423n4/2022-04-backd/blob/c856714a50437cb33240a5964b63687c9876275b/backd/contracts/vault/VaultStorage.sol#L9
The instances below point to the second access of a state variable within a function. Caching will replace each Gwarmaccess (100 gas) with a much cheaper stack read. Less obvious fixes/optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, or having local caches of state variable contracts/addresses.
File: contracts/actions/topup/TopUpAction.sol #1 236 _positions[msg.sender][account][protocol] = record;
File: contracts/Controller.sol #2 49 inflationManager.whitelistGauge(lpGauge);
File: contracts/Controller.sol #3 69 inflationManager.removeStakerVaultFromInflation(stakerVault, lpToken);
File: contracts/CvxCrvRewardsLocker.sol #4 152 emit NewTreasury(treasury);
File: contracts/pool/LiquidityPool.sol #5 446 staker.unstakeFor(msg.sender, msg.sender, redeemLpTokens - lpBalance_);
File: contracts/pool/LiquidityPool.sol #6 160 addressProvider.isStakerVault(to, address(lpToken)) ||
File: contracts/pool/LiquidityPool.sol #7 527 lpToken.mint(account, mintedLp);
File: contracts/StakerVault.sol #8 331 uint256 oldBal = IERC20(token).balanceOf(address(this));
File: contracts/StakerVault.sol #9 376 uint256 oldBal = IERC20(token).balanceOf(address(this));
File: contracts/StakerVault.sol #10 173 _allowances[src][spender] = allowanceNew;
File: contracts/StakerVault.sol #11 388 _allowances[src][msg.sender] -= unstaked;
File: contracts/vault/VaultReserve.sol #12 60 _balances[msg.sender][token] += received;
File: contracts/vault/VaultReserve.sol #13 77 _balances[msg.sender][token] -= amount;
+=
costs more gas than = +
for state variablesFile: contracts/StakerVault.sol #1 344 strategiesTotalStaked += staked;
File: contracts/StakerVault.sol #2 346 _poolTotalStaked += staked;
File: contracts/StakerVault.sol #3 393 strategiesTotalStaked -= unstaked;
File: contracts/StakerVault.sol #4 395 _poolTotalStaked -= unstaked;
unchecked {}
for subtractions where the operands cannot underflow because of a previous require()
require(a <= b); x = b - a
=> require(a <= b); unchecked { x = b - a }
File: contracts/GasBank.sol #1 76 require(currentBalance - amount >= ethRequired, Error.NOT_ENOUGH_FUNDS);
File: contracts/StakerVault.sol #2 163 uint256 allowanceNew = startingAllowance - amount;
File: contracts/StakerVault.sol #3 164 uint256 srcTokensNew = srcTokens - amount;
.length
should not be looked up in every loop of a for
-loopEven memory arrays incur the overhead of bit tests and bit shifts to calculate the array length. Storage array length checks incur an extra Gwarmaccess (100 gas) PER-LOOP.
File: contracts/access/RoleManager.sol #1 80 for (uint256 i = 0; i < roles.length; i++) {
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 135 for (uint256 i = 0; i < assets.length; i++) {
File: contracts/actions/topup/handlers/CTokenRegistry.sol #3 61 for (uint256 i = 0; i < ctokens.length; i++) {
File: contracts/actions/topup/TopUpAction.sol #4 188 for (uint256 i = 0; i < protocols.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #5 43 for (uint256 i = 0; i < users.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #6 46 for (uint256 j = 0; j < positions.length; j++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #7 72 for (uint256 i = 0; i < keys.length; i++) {
File: contracts/StakerVault.sol #8 260 for (uint256 i = 0; i < actions.length; i++) {
++i
/i++
should be unchecked{++i}
/unchecked{++i}
when it is not possible for them to overflow, as is the case when used in for
- and while
-loopsFile: contracts/access/RoleManager.sol #1 80 for (uint256 i = 0; i < roles.length; i++) {
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 135 for (uint256 i = 0; i < assets.length; i++) {
File: contracts/actions/topup/handlers/CTokenRegistry.sol #3 61 for (uint256 i = 0; i < ctokens.length; i++) {
File: contracts/actions/topup/TopUpAction.sol #4 188 for (uint256 i = 0; i < protocols.length; i++) {
File: contracts/actions/topup/TopUpAction.sol #5 456 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpAction.sol #6 479 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpAction.sol #7 506 for (uint256 i = 0; i < howMany; i++) {
File: contracts/actions/topup/TopUpAction.sol #8 891 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #9 43 for (uint256 i = 0; i < users.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #10 46 for (uint256 j = 0; j < positions.length; j++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #11 72 for (uint256 i = 0; i < keys.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #12 93 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #13 165 for (uint256 i = 0; i < length; i++) {
File: contracts/Controller.sol #14 117 for (uint256 i = 0; i < numActions; i++) {
File: contracts/StakerVault.sol #15 260 for (uint256 i = 0; i < actions.length; i++) {
File: contracts/strategies/ConvexStrategyBase.sol #16 313 for (uint256 i = 0; i < _rewardTokens.length(); i++) {
File: contracts/strategies/ConvexStrategyBase.sol #17 380 for (uint256 i = 0; i < _rewardTokens.length(); i++) {
require()
/revert()
strings longer than 32 bytes cost extra gasFile: contracts/actions/topup/TopUpAction.sol #1 67 require(amountLeft == 0, Error.INSUFFICIENT_UPDATE_BALANCE);
File: contracts/actions/topup/TopUpAction.sol #2 218 require(isUsable(record.depositToken), Error.TOKEN_NOT_USABLE);
File: contracts/actions/topup/TopUpAction.sol #3 575 require( 576 vars.estimatedRequiredWeiForGas <= 577 vars.estimatedRequiredGas * vars.userGasPrice + maxWeiForGas, 578 Error.ESTIMATED_GAS_TOO_HIGH 579 );
File: contracts/actions/topup/TopUpAction.sol #4 583 require( 584 vars.gasBankBalance + maxWeiForGas >= vars.estimatedRequiredWeiForGas, 585 Error.GAS_BANK_BALANCE_TOO_LOW 586 );
File: contracts/AddressProvider.sol #5 285 require(!_stakerVaults.contains(token), Error.STAKER_VAULT_EXISTS);
File: contracts/CvxCrvRewardsLocker.sol #6 83 require( 84 _spendRatio <= ICvxLocker(CVX_LOCKER).maximumBoostPayment(), 85 Error.EXCEEDS_MAX_BOOST 86 );
File: contracts/CvxCrvRewardsLocker.sol #7 135 require(!prepareWithdrawal, Error.PREPARED_WITHDRAWAL);
File: contracts/pool/LiquidityPool.sol #8 137 require(ILpToken(_lpToken).minter() == address(this), Error.INVALID_MINTER);
File: contracts/pool/LiquidityPool.sol #9 400 require(depositCap != _depositCap, Error.SAME_AS_CURRENT);
File: contracts/pool/LiquidityPool.sol #10 562 require(redeemUnderlying >= minRedeemAmount, Error.NOT_ENOUGH_FUNDS_WITHDRAWN);
File: contracts/pool/PoolFactory.sol #11 159 require(vars.poolImplementation != address(0), Error.INVALID_POOL_IMPLEMENTATION);
File: contracts/pool/PoolFactory.sol #12 162 require(vars.lpTokenImplementation != address(0), Error.INVALID_LP_TOKEN_IMPLEMENTATION);
File: contracts/pool/PoolFactory.sol #13 165 require(vars.vaultImplementation != address(0), Error.INVALID_VAULT_IMPLEMENTATION);
File: contracts/pool/PoolFactory.sol #14 170 require( 171 vars.stakerVaultImplementation != address(0), 172 Error.INVALID_STAKER_VAULT_IMPLEMENTATION 173 );
File: contracts/pool/PoolFactory.sol #15 180 require( 181 ILiquidityPool(vars.poolImplementation).getUnderlying() == address(0), 182 Error.INVALID_POOL_IMPLEMENTATION 183 );
File: contracts/utils/Preparable.sol #16 110 require(block.timestamp >= deadline, Error.DEADLINE_NOT_REACHED);
File: contracts/vault/Vault.sol #17 165 require(IPausable(pool).isPaused(), Error.POOL_NOT_PAUSED);
File: contracts/vault/Vault.sol #18 762 require( 763 reserveFee + strategistFee <= ScaledMath.ONE, 764 "sum of strategist fee and reserve fee should be below 1" 765 );
File: contracts/actions/topup/TopUpAction.sol #1 500 if (cursor >= length) return (new address[](0), 0);
File: contracts/actions/topup/TopUpAction.sol #2 510 return (usersWithPositions_, cursor + howMany);
File: contracts/actions/topup/TopUpAction.sol #3 500 if (cursor >= length) return (new address[](0), 0);
File: contracts/actions/topup/TopUpAction.sol #4 510 return (usersWithPositions_, cursor + howMany);
File: contracts/actions/topup/TopUpAction.sol #5 763 return topUpHandler.getUserFactor(account, extra);
File: contracts/actions/topup/TopUpKeeperHelper.sol #6 42 if (users.length == 0) return (_shortenTopups(executableTopups, topupsAdded), 0);
File: contracts/actions/topup/TopUpKeeperHelper.sol #7 52 if (topupsAdded == howMany) return (executableTopups, cursor + i + offset);
File: contracts/actions/topup/TopUpKeeperHelper.sol #8 42 if (users.length == 0) return (_shortenTopups(executableTopups, topupsAdded), 0);
File: contracts/actions/topup/TopUpKeeperHelper.sol #9 52 if (topupsAdded == howMany) return (executableTopups, cursor + i + offset);
File: contracts/oracles/ChainlinkUsdWrapper.sol #10 56 return (roundId_, (answer_ * _ethPrice()) / 1e8, startedAt_, updatedAt_, answeredInRound_);
File: contracts/oracles/ChainlinkUsdWrapper.sol #11 56 return (roundId_, (answer_ * _ethPrice()) / 1e8, startedAt_, updatedAt_, answeredInRound_);
File: contracts/oracles/ChainlinkUsdWrapper.sol #12 56 return (roundId_, (answer_ * _ethPrice()) / 1e8, startedAt_, updatedAt_, answeredInRound_);
File: contracts/oracles/ChainlinkUsdWrapper.sol #13 56 return (roundId_, (answer_ * _ethPrice()) / 1e8, startedAt_, updatedAt_, answeredInRound_);
File: contracts/oracles/ChainlinkUsdWrapper.sol #14 56 return (roundId_, (answer_ * _ethPrice()) / 1e8, startedAt_, updatedAt_, answeredInRound_);
File: contracts/strategies/StrategySwapper.sol #15 303 return curvePool_.coins(1) == token_ ? (0, 1) : (1, 0);
File: contracts/strategies/StrategySwapper.sol #16 303 return curvePool_.coins(1) == token_ ? (0, 1) : (1, 0);
File: contracts/strategies/StrategySwapper.sol #17 317 return 318 wethAmount_ 319 .scaledDiv(_addressProvider.getOracleProvider().getPriceETH(token_)) 320 .scaledMul(slippageTolerance) / _decimalMultiplier(token_);
File: contracts/strategies/StrategySwapper.sol #18 334 return 335 tokenAmount_ 336 .scaledMul(_addressProvider.getOracleProvider().getPriceETH(token_)) 337 .scaledMul(slippageTolerance) * _decimalMultiplier(token_);
bool
s for storage incurs overhead// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27
Use uint256(1)
and uint256(2)
for true/false
File: contracts/CvxCrvRewardsLocker.sol #1 40 bool public prepareWithdrawal;
File: contracts/StakerVault.sol #2 55 mapping(address => bool) public strategies;
File: contracts/strategies/ConvexStrategyBase.sol #3 48 bool public isShutdown; // If the strategy is shutdown, stops all deposits
File: contracts/strategies/StrategySwapper.sol #4 32 mapping(address => bool) public swapViaUniswap; // If Uniswap should be used over Sushiswap for swaps
File: contracts/utils/Pausable.sol #5 7 bool public isPaused;
File: contracts/vault/VaultStorage.sol #6 14 bool public strategyActive;
Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
File: contracts/access/AuthorizationBase.sol #1 2 pragma solidity 0.8.9;
File: contracts/access/Authorization.sol #2 2 pragma solidity 0.8.9;
File: contracts/access/RoleManager.sol #3 2 pragma solidity 0.8.9;
File: contracts/actions/topup/handlers/AaveHandler.sol #4 2 pragma solidity 0.8.9;
File: contracts/actions/topup/handlers/BaseHandler.sol #5 2 pragma solidity 0.8.9;
File: contracts/actions/topup/handlers/CompoundHandler.sol #6 2 pragma solidity 0.8.9;
File: contracts/actions/topup/handlers/CTokenRegistry.sol #7 2 pragma solidity 0.8.9;
File: contracts/actions/topup/TopUpActionFeeHandler.sol #8 2 pragma solidity 0.8.9;
File: contracts/actions/topup/TopUpAction.sol #9 2 pragma solidity 0.8.9;
File: contracts/actions/topup/TopUpKeeperHelper.sol #10 2 pragma solidity 0.8.9;
File: contracts/AddressProvider.sol #11 2 pragma solidity 0.8.9;
File: contracts/Controller.sol #12 2 pragma solidity 0.8.9;
File: contracts/CvxCrvRewardsLocker.sol #13 2 pragma solidity 0.8.9;
File: contracts/GasBank.sol #14 2 pragma solidity 0.8.9;
File: contracts/LpToken.sol #15 2 pragma solidity 0.8.9;
File: contracts/oracles/ChainlinkOracleProvider.sol #16 2 pragma solidity 0.8.9;
File: contracts/oracles/ChainlinkUsdWrapper.sol #17 2 pragma solidity 0.8.9;
File: contracts/oracles/OracleProviderExtensions.sol #18 2 pragma solidity 0.8.9;
File: contracts/pool/Erc20Pool.sol #19 2 pragma solidity 0.8.9;
File: contracts/pool/EthPool.sol #20 2 pragma solidity 0.8.9;
File: contracts/pool/LiquidityPool.sol #21 2 pragma solidity 0.8.9;
File: contracts/pool/PoolFactory.sol #22 2 pragma solidity 0.8.9;
File: contracts/StakerVault.sol #23 2 pragma solidity 0.8.9;
File: contracts/strategies/BkdEthCvx.sol #24 2 pragma solidity 0.8.9;
File: contracts/strategies/BkdTriHopCvx.sol #25 2 pragma solidity 0.8.9;
File: contracts/strategies/ConvexStrategyBase.sol #26 2 pragma solidity 0.8.9;
File: contracts/strategies/StrategySwapper.sol #27 2 pragma solidity 0.8.9;
File: contracts/utils/CvxMintAmount.sol #28 2 pragma solidity 0.8.9;
File: contracts/utils/Pausable.sol #29 2 pragma solidity 0.8.9;
File: contracts/utils/Preparable.sol #30 2 pragma solidity 0.8.9;
File: contracts/vault/Erc20Vault.sol #31 2 pragma solidity 0.8.9;
File: contracts/vault/EthVault.sol #32 2 pragma solidity 0.8.9;
File: contracts/vault/VaultReserve.sol #33 2 pragma solidity 0.8.9;
File: contracts/vault/Vault.sol #34 2 pragma solidity 0.8.9;
File: contracts/vault/VaultStorage.sol #35 2 pragma solidity 0.8.9;
File: libraries/AddressProviderHelpers.sol #36 2 pragma solidity 0.8.9;
File: libraries/AddressProviderMeta.sol #37 2 pragma solidity 0.8.9;
File: libraries/Errors.sol #38 2 pragma solidity 0.8.9;
File: libraries/ScaledMath.sol #39 2 pragma solidity 0.8.9;
> 0
costs more gas than != 0
when used on a uint
in a require()
statementFile: contracts/actions/topup/TopUpActionFeeHandler.sol #1 123 require(totalClaimable > 0, Error.NOTHING_TO_CLAIM);
File: contracts/pool/LiquidityPool.sol #2 401 require(_depositCap > 0, Error.INVALID_AMOUNT);
File: contracts/pool/LiquidityPool.sol #3 471 require(underlyingAmount > 0, Error.INVALID_AMOUNT);
File: contracts/pool/LiquidityPool.sol #4 549 require(redeemLpTokens > 0, Error.INVALID_AMOUNT);
File: contracts/vault/Vault.sol #5 164 require(amount > 0, Error.INVALID_AMOUNT);
File: contracts/access/RoleManager.sol #1 80 for (uint256 i = 0; i < roles.length; i++) {
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 135 for (uint256 i = 0; i < assets.length; i++) {
File: contracts/actions/topup/handlers/CTokenRegistry.sol #3 61 for (uint256 i = 0; i < ctokens.length; i++) {
File: contracts/actions/topup/TopUpAction.sol #4 188 for (uint256 i = 0; i < protocols.length; i++) {
File: contracts/actions/topup/TopUpAction.sol #5 452 uint256 totalEthRequired = 0;
File: contracts/actions/topup/TopUpAction.sol #6 456 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpAction.sol #7 479 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpAction.sol #8 506 for (uint256 i = 0; i < howMany; i++) {
File: contracts/actions/topup/TopUpAction.sol #9 891 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #10 43 for (uint256 i = 0; i < users.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #11 46 for (uint256 j = 0; j < positions.length; j++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #12 72 for (uint256 i = 0; i < keys.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #13 93 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #14 165 for (uint256 i = 0; i < length; i++) {
File: contracts/Controller.sol #15 114 uint256 totalEthRequired = 0;
File: contracts/Controller.sol #16 117 for (uint256 i = 0; i < numActions; i++) {
File: contracts/pool/LiquidityPool.sol #17 483 uint256 currentFeeRatio = 0;
File: contracts/StakerVault.sol #18 144 uint256 startingAllowance = 0;
File: contracts/StakerVault.sol #19 260 for (uint256 i = 0; i < actions.length; i++) {
File: contracts/strategies/ConvexStrategyBase.sol #20 313 for (uint256 i = 0; i < _rewardTokens.length(); i++) {
File: contracts/strategies/ConvexStrategyBase.sol #21 380 for (uint256 i = 0; i < _rewardTokens.length(); i++) {
File: contracts/vault/Vault.sol #22 135 uint256 allocatedUnderlying = 0;
File: contracts/vault/Vault.sol #23 583 uint256 strategistShare = 0;
internal
functions only called once can be inlined to save gasFile: contracts/actions/topup/handlers/CompoundHandler.sol #1 105 function _repayAnyDebt( 106 address account, 107 address underlying, 108 uint256 maximum, 109 CToken ctoken 110 ) internal returns (uint256) {
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 128 function _getAccountBorrowsAndSupply(address account) internal view returns (uint256, uint256) {
File: contracts/actions/topup/TopUpAction.sol #3 840 function _payFees( 841 address payer, 842 address beneficiary, 843 uint256 feeAmount, 844 address depositToken
File: contracts/actions/topup/TopUpAction.sol #4 861 function _lockFunds( 862 address payer, 863 address token, 864 uint256 lockAmount, 865 uint256 depositAmount
File: contracts/actions/topup/TopUpAction.sol #5 884 function _removeUserPosition( 885 address payer, 886 bytes32 account, 887 bytes32 protocol
File: contracts/actions/topup/TopUpAction.sol #6 906 function _approve(address token, address spender) internal {
File: contracts/actions/topup/TopUpAction.sol #7 914 function _calcExchangeAmount( 915 address token, 916 address actionToken, 917 uint256 amount 918 ) internal view returns (uint256) {
File: contracts/actions/topup/TopUpAction.sol #8 922 function _getSwapper(address underlying, address actionToken) internal view returns (ISwapper) {
File: contracts/actions/topup/TopUpAction.sol #9 932 function _isSwappable(address depositToken, address toToken) internal view returns (bool) {
File: contracts/AddressProvider.sol #10 422 function _addKnownAddressKey(bytes32 key, AddressProviderMeta.Meta memory meta) internal {
File: contracts/CvxCrvRewardsLocker.sol #11 273 function _stakeCvxCrv() internal returns (bool) {
File: contracts/pool/Erc20Pool.sol #12 38 function _getBalanceUnderlying() internal view override returns (uint256) {
File: contracts/pool/Erc20Pool.sol #13 42 function _getBalanceUnderlying(bool) internal view override returns (uint256) {
File: contracts/pool/EthPool.sol #14 33 function _getBalanceUnderlying() internal view override returns (uint256) {
File: contracts/pool/EthPool.sol #15 37 function _getBalanceUnderlying(bool transferInDone) internal view override returns (uint256) {
File: contracts/strategies/BkdEthCvx.sol #16 130 function _minLpAccepted(uint256 _underlyingAmount) internal view returns (uint256) {
File: contracts/strategies/BkdEthCvx.sol #17 139 function _maxLpBurned(uint256 _underlyingAmount) internal view returns (uint256) {
File: contracts/strategies/BkdEthCvx.sol #18 148 function _minUnderlyingAccepted(uint256 _lpAmount) internal view returns (uint256) {
File: contracts/strategies/BkdTriHopCvx.sol #19 146 function _deposit() internal override returns (bool) {
File: contracts/strategies/BkdTriHopCvx.sol #20 242 function _minLpAccepted(uint256 _hopLpAmount) internal view returns (uint256) {
File: contracts/strategies/BkdTriHopCvx.sol #21 251 function _maxLpBurned(uint256 _hopLpAmount) internal view returns (uint256) {
File: contracts/strategies/BkdTriHopCvx.sol #22 260 function _minHopLpAcceptedFromWithdraw(uint256 _lpAmount) internal view returns (uint256) {
File: contracts/strategies/BkdTriHopCvx.sol #23 269 function _minHopLpAcceptedFromDeposit(uint256 _underlyingAmount) 270 internal 271 view 272 returns (uint256)
File: contracts/strategies/BkdTriHopCvx.sol #24 285 function _maxHopLpBurned(uint256 _underlyingAmount) internal view returns (uint256) {
File: contracts/strategies/BkdTriHopCvx.sol #25 297 function _minUnderlyingAccepted(uint256 _hopLpAmount) internal view returns (uint256) {
File: contracts/strategies/StrategySwapper.sol #26 227 function _tokenToWethAmountOut(address token_, uint256 amount_) 228 internal 229 view 230 returns (uint256)
File: contracts/strategies/StrategySwapper.sol #27 257 function _wethToTokenAmountOut(address token_, uint256 amount_) 258 internal 259 view 260 returns (uint256)
calldata
instead of memory
for read-only arguments in external
functions saves gasFile: contracts/access/RoleManager.sol #1 73 function hasAnyRole(bytes32[] memory roles, address account)
File: contracts/actions/topup/handlers/AaveHandler.sol #2 40 bytes memory extra
File: contracts/actions/topup/handlers/AaveHandler.sol #3 69 function getUserFactor(bytes32 account, bytes memory) external view override returns (uint256) {
File: contracts/actions/topup/handlers/CompoundHandler.sol #4 54 bytes memory extra
File: contracts/actions/topup/handlers/CompoundHandler.sol #5 90 function getUserFactor(bytes32 account, bytes memory) external view override returns (uint256) {
File: contracts/actions/topup/TopUpAction.sol #6 207 Record memory record
File: contracts/LpToken.sol #7 29 string memory name_,
File: contracts/LpToken.sol #8 30 string memory symbol_,
File: contracts/pool/EthPool.sol #9 13 string memory name_,
++i
costs less gas than ++i
, especially when it's used in for
-loops (--i
/i--
too)File: contracts/access/RoleManager.sol #1 80 for (uint256 i = 0; i < roles.length; i++) {
File: contracts/actions/topup/handlers/CompoundHandler.sol #2 135 for (uint256 i = 0; i < assets.length; i++) {
File: contracts/actions/topup/handlers/CTokenRegistry.sol #3 61 for (uint256 i = 0; i < ctokens.length; i++) {
File: contracts/actions/topup/TopUpAction.sol #4 188 for (uint256 i = 0; i < protocols.length; i++) {
File: contracts/actions/topup/TopUpAction.sol #5 456 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpAction.sol #6 479 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpAction.sol #7 506 for (uint256 i = 0; i < howMany; i++) {
File: contracts/actions/topup/TopUpAction.sol #8 891 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #9 43 for (uint256 i = 0; i < users.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #10 46 for (uint256 j = 0; j < positions.length; j++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #11 72 for (uint256 i = 0; i < keys.length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #12 93 for (uint256 i = 0; i < length; i++) {
File: contracts/actions/topup/TopUpKeeperHelper.sol #13 165 for (uint256 i = 0; i < length; i++) {
File: contracts/Controller.sol #14 117 for (uint256 i = 0; i < numActions; i++) {
File: contracts/StakerVault.sol #15 260 for (uint256 i = 0; i < actions.length; i++) {
File: contracts/strategies/ConvexStrategyBase.sol #16 313 for (uint256 i = 0; i < _rewardTokens.length(); i++) {
File: contracts/strategies/ConvexStrategyBase.sol #17 380 for (uint256 i = 0; i < _rewardTokens.length(); i++) {
require()
statements that use &&
saves gasSee this issue for an example
File: contracts/actions/topup/TopUpAction.sol #1 359 require( 360 newSwapperSlippage >= _MIN_SWAPPER_SLIPPAGE && 361 newSwapperSlippage <= _MAX_SWAPPER_SLIPPAGE, 362 Error.INVALID_AMOUNT 363 );
File: contracts/actions/topup/TopUpAction.sol #2 676 require(vars.success && abi.decode(vars.topupResult, (bool)), Error.TOP_UP_FAILED);
File: contracts/strategies/ConvexStrategyBase.sol #3 273 require( 274 token_ != address(_CVX) && token_ != address(underlying) && token_ != address(_CRV), 275 Error.INVALID_TOKEN_TO_ADD 276 );
uints
/ints
smaller than 32 bytes (256 bits) incurs overheadWhen using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
File: contracts/actions/topup/handlers/AaveHandler.sol #1 19 uint16 public constant BACKD_REFERRAL_CODE = 62314;
File: contracts/actions/topup/TopUpAction.sol #2 127 uint128 totalTopUpAmount;
File: contracts/actions/topup/TopUpAction.sol #3 206 uint128 depositAmount,
File: contracts/CvxCrvRewardsLocker.sol #4 43 int128 private constant _CRV_INDEX = 0;
File: contracts/CvxCrvRewardsLocker.sol #5 44 int128 private constant _CVX_CRV_INDEX = 1;
File: contracts/LpToken.sol #6 13 uint8 private _decimals;
File: contracts/LpToken.sol #7 31 uint8 decimals_,
File: contracts/LpToken.sol #8 74 function decimals() public view virtual override returns (uint8) {
File: contracts/oracles/ChainlinkOracleProvider.sol #9 61 uint8 decimals = AggregatorV2V3Interface(feed).decimals();
File: contracts/oracles/ChainlinkUsdWrapper.sol #10 11 uint80 roundId,
File: contracts/oracles/ChainlinkUsdWrapper.sol #11 15 uint80 answeredInRound
File: contracts/oracles/ChainlinkUsdWrapper.sol #12 18 function decimals() external view returns (uint8);
File: contracts/oracles/ChainlinkUsdWrapper.sol #13 30 uint8 private immutable _decimals;
File: contracts/oracles/ChainlinkUsdWrapper.sol #14 42 uint80 roundId,
File: contracts/oracles/ChainlinkUsdWrapper.sol #15 46 uint80 answeredInRound
File: contracts/oracles/ChainlinkUsdWrapper.sol #16 50 uint80 roundId_,
File: contracts/oracles/ChainlinkUsdWrapper.sol #17 54 uint80 answeredInRound_
File: contracts/oracles/ChainlinkUsdWrapper.sol #18 59 function decimals() external view override returns (uint8) {
File: contracts/pool/LiquidityPool.sol #19 37 uint64 timeToWait;
File: contracts/pool/LiquidityPool.sol #20 38 uint64 feeRatio;
File: contracts/pool/LiquidityPool.sol #21 39 uint64 lastActionTimestamp;
File: contracts/pool/PoolFactory.sol #22 49 uint8 decimals;
File: contracts/StakerVault.sol #23 296 function decimals() external view returns (uint8) {
private
rather than public
for constants, saves gasIf needed, the value can be read from the verified contract source code
File: contracts/actions/topup/handlers/AaveHandler.sol #1 19 uint16 public constant BACKD_REFERRAL_CODE = 62314;
File: contracts/strategies/BkdTriHopCvx.sol #2 21 uint256 public immutable curveHopIndex; // Underlying index in Curve Pool
File: contracts/vault/Vault.sol #3 44 uint256 public constant MAX_PERFORMANCE_FEE = 0.5e18;
File: contracts/vault/Vault.sol #4 45 uint256 public constant MAX_DEVIATION_BOUND = 0.5e18;
File: contracts/vault/Vault.sol #5 46 uint256 public constant STRATEGY_DELAY = 5 days;
require()
/revert()
checks should be refactored to a modifier or functionFile: contracts/actions/topup/TopUpActionFeeHandler.sol #1 206 require( 207 pendingUInts256[_TREASURY_FEE_FRACTION_KEY] + 208 pendingUInts256[_KEEPER_FEE_FRACTION_KEY] <= 209 ScaledMath.ONE, 210 Error.INVALID_AMOUNT 211 );
File: contracts/actions/topup/TopUpAction.sol #2 553 require(position.threshold != 0, Error.NO_POSITION_EXISTS);
File: contracts/AddressProvider.sol #3 249 require(!meta.frozen, Error.ADDRESS_FROZEN);
File: contracts/GasBank.sol #4 69 require( 70 msg.sender == account || addressProvider.isAction(msg.sender), 71 Error.UNAUTHORIZED_ACCESS 72 );
File: contracts/pool/LiquidityPool.sol #5 399 require(isCapped(), Error.NOT_CAPPED);
File: contracts/StakerVault.sol #6 224 require(controller.addressProvider().isAction(msg.sender), Error.UNAUTHORIZED_ACCESS);
File: contracts/strategies/ConvexStrategyBase.sol #7 215 require(communityReserve != address(0), "Community reserve must be set");
File: contracts/strategies/StrategySwapper.sol #8 139 require(token_ != address(0), Error.ZERO_ADDRESS_NOT_ALLOWED);
File: contracts/utils/Preparable.sol #9 98 require(deadlines[key] != 0, Error.DEADLINE_NOT_ZERO);
require()
or revert()
statements that check input arguments should be at the top of the functionChecks that involve constants should come before checks that involve state variables
File: contracts/actions/topup/TopUpActionFeeHandler.sol #1 68 require(_keeperGauge != address(0), Error.ZERO_ADDRESS_NOT_ALLOWED);
File: contracts/Controller.sol #2 33 require(_inflationManager != address(0), Error.INVALID_ARGUMENT);
File: contracts/pool/LiquidityPool.sol #3 401 require(_depositCap > 0, Error.INVALID_AMOUNT);
File: contracts/vault/Vault.sol #4 195 require(strategy_ != address(0), Error.ZERO_ADDRESS_NOT_ALLOWED);
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...}
=> if(!x){if(y){...}else{...}}
)
File: contracts/actions/topup/TopUpAction.sol #1 176 receive() external payable { 177 // solhint-disable-previous-line no-empty-blocks 178 }
File: contracts/pool/EthPool.sol #2 10 receive() external payable {}
File: contracts/strategies/BkdEthCvx.sol #3 46 receive() external payable {}
File: contracts/strategies/StrategySwapper.sol #4 45 receive() external payable {}
File: contracts/vault/EthVault.sol #5 13 receive() external payable {}
revert()
/require()
strings to save deployment gasFile: contracts/access/AuthorizationBase.sol (various lines) #1
File: contracts/access/RoleManager.sol (various lines) #2
File: contracts/actions/topup/handlers/AaveHandler.sol (various lines) #3
File: contracts/actions/topup/handlers/CompoundHandler.sol (various lines) #4
File: contracts/actions/topup/handlers/CTokenRegistry.sol (various lines) #5
File: contracts/actions/topup/TopUpActionFeeHandler.sol (various lines) #6
File: contracts/actions/topup/TopUpAction.sol (various lines) #7
File: contracts/AddressProvider.sol (various lines) #8
File: contracts/Controller.sol (various lines) #9
File: contracts/CvxCrvRewardsLocker.sol (various lines) #10
File: contracts/GasBank.sol (various lines) #11
File: contracts/LpToken.sol (various lines) #12
File: contracts/oracles/ChainlinkOracleProvider.sol (various lines) #13
File: contracts/pool/Erc20Pool.sol (various lines) #14
File: contracts/pool/EthPool.sol (various lines) #15
File: contracts/pool/LiquidityPool.sol (various lines) #16
File: contracts/pool/PoolFactory.sol (various lines) #17
File: contracts/StakerVault.sol (various lines) #18
File: contracts/strategies/BkdTriHopCvx.sol (various lines) #19
File: contracts/strategies/ConvexStrategyBase.sol (various lines) #20
File: contracts/strategies/StrategySwapper.sol (various lines) #21
File: contracts/utils/Pausable.sol (various lines) #22
File: contracts/utils/Preparable.sol (various lines) #23
File: contracts/vault/Erc20Vault.sol (various lines) #24
File: contracts/vault/VaultReserve.sol (various lines) #25
File: contracts/vault/Vault.sol (various lines) #26
payable
If a function modifier such as onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function as payable
will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.
File: contracts/access/RoleManager.sol #1 35 function grantRole(bytes32 role, address account) external onlyGovernance {
File: contracts/access/RoleManager.sol #2 39 function addGovernor(address newGovernor) external onlyGovernance {
File: contracts/access/RoleManager.sol #3 43 function renounceGovernance() external onlyGovernance {
File: contracts/access/RoleManager.sol #4 48 function addGaugeZap(address zap) external onlyGovernance {
File: contracts/access/RoleManager.sol #5 109 function revokeRole(bytes32 role, address account) public onlyGovernance {
File: contracts/actions/topup/TopUpActionFeeHandler.sol #6 61 function setInitialKeeperGaugeForToken(address lpToken, address _keeperGauge) 62 external 63 override 64 onlyGovernance 65 returns (bool)
File: contracts/actions/topup/TopUpActionFeeHandler.sol #7 150 function prepareKeeperFee(uint256 newKeeperFee) external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpActionFeeHandler.sol #8 170 function resetKeeperFee() external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpActionFeeHandler.sol #9 174 function prepareKeeperGauge(address lpToken, address newKeeperGauge) 175 external 176 onlyGovernance 177 returns (bool)
File: contracts/actions/topup/TopUpActionFeeHandler.sol #10 186 function resetKeeperGauge(address lpToken) external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpActionFeeHandler.sol #11 195 function prepareTreasuryFee(uint256 newTreasuryFee) external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpActionFeeHandler.sol #12 215 function resetTreasuryFee() external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #13 180 function initialize( 181 address feeHandler, 182 bytes32[] calldata protocols, 183 address[] calldata handlers 184 ) external initializer onlyGovernance {
File: contracts/actions/topup/TopUpAction.sol #14 318 function resetTopUpHandler(bytes32 protocol) external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #15 327 function prepareActionFee(uint256 newActionFee) external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #16 345 function resetActionFee() external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #17 354 function prepareSwapperSlippage(uint256 newSwapperSlippage) 355 external 356 onlyGovernance 357 returns (bool)
File: contracts/actions/topup/TopUpAction.sol #18 380 function resetSwapperSlippage() external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #19 390 function prepareFeeHandler(address handler) external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #20 407 function resetFeeHandler() external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #21 416 function prepareEstimatedGasUsage(uint256 gasUsage) external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #22 432 function resetGasUsage() external onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #23 442 function addUsableToken(address token) external override onlyGovernance returns (bool) {
File: contracts/actions/topup/TopUpAction.sol #24 742 function prepareTopUpHandler(bytes32 protocol, address newHandler) 743 public 744 onlyGovernance 745 returns (bool)
File: contracts/AddressProvider.sol #25 63 function addFeeHandler(address feeHandler) external onlyGovernance returns (bool) {
File: contracts/AddressProvider.sol #26 69 function removeFeeHandler(address feeHandler) external onlyGovernance returns (bool) {
File: contracts/AddressProvider.sol #27 79 function addAction(address action) external onlyGovernance returns (bool) {
File: contracts/AddressProvider.sol #28 91 function addPool(address pool) 92 external 93 override 94 onlyRoles2(Roles.POOL_FACTORY, Roles.GOVERNANCE)
File: contracts/AddressProvider.sol #29 115 function removePool(address pool) external override onlyRole(Roles.CONTROLLER) returns (bool) {
File: contracts/AddressProvider.sol #30 156 function updateVault(address previousVault, address newVault) external onlyRole(Roles.POOL) {
File: contracts/AddressProvider.sol #31 201 function initializeAddress( 202 bytes32 key, 203 address initialAddress, 204 bool freezable 205 ) public override onlyGovernance {
File: contracts/AddressProvider.sol #32 215 function initializeAndFreezeAddress(bytes32 key, address initialAddress) 216 external 217 override 218 onlyGovernance
File: contracts/AddressProvider.sol #33 228 function freezeAddress(bytes32 key) external override onlyGovernance {
File: contracts/AddressProvider.sol #34 242 function prepareAddress(bytes32 key, address newAddress) 243 external 244 override 245 onlyGovernance 246 returns (bool)
File: contracts/AddressProvider.sol #35 267 function resetAddress(bytes32 key) external onlyGovernance returns (bool) {
File: contracts/AddressProvider.sol #36 277 function addStakerVault(address stakerVault) 278 external 279 override 280 onlyRole(Roles.CONTROLLER) 281 returns (bool)
File: contracts/Controller.sol #37 31 function setInflationManager(address _inflationManager) external onlyGovernance {
File: contracts/Controller.sol #38 37 function addStakerVault(address stakerVault) 38 external 39 override 40 onlyRoles2(Roles.GOVERNANCE, Roles.POOL_FACTORY) 41 returns (bool)
File: contracts/Controller.sol #39 60 function removePool(address pool) external override onlyGovernance returns (bool) {
File: contracts/Controller.sol #40 79 function prepareKeeperRequiredStakedBKD(uint256 amount) external override onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #41 82 function setSpendRatio(uint256 _spendRatio) external onlyGovernance returns (bool) {
File: contracts/CvxCrvRewardsLocker.sol #42 119 function setWithdrawalFlag() external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #43 126 function resetWithdrawalFlag() external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #44 150 function setTreasury(address _treasury) external onlyGovernance returns (bool) {
File: contracts/CvxCrvRewardsLocker.sol #45 160 function withdraw(address token) external onlyGovernance returns (bool) {
File: contracts/CvxCrvRewardsLocker.sol #46 170 function withdrawCvxCrv(uint256 amount) external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #47 178 function unstakeCvxCrv() external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #48 182 function unstakeCvxCrv(uint256 amount, bool withdrawal) external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #49 189 function setDelegate(address delegateContract, address delegate) external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #50 196 function clearDelegate(address delegateContract) external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #51 200 function forfeitRewards(address token, uint256 index) external onlyGovernance {
File: contracts/CvxCrvRewardsLocker.sol #52 222 function withdraw(address token, uint256 amount) public onlyGovernance returns (bool) {
File: contracts/CvxCrvRewardsLocker.sol #53 230 function unstakeCvxCrv(bool withdrawal) public onlyGovernance {
File: contracts/LpToken.sol #54 46 function mint(address account, uint256 amount) external override onlyMinter {
File: contracts/LpToken.sol #55 64 function burn(address owner, uint256 burnAmount) 65 external 66 override 67 onlyMinter 68 returns (uint256)
File: contracts/oracles/ChainlinkOracleProvider.sol #56 29 function setFeed(address asset, address feed) external override onlyGovernance {
File: contracts/oracles/ChainlinkOracleProvider.sol #57 40 function setStalePriceDelay(uint256 stalePriceDelay_) external override onlyGovernance {
File: contracts/pool/LiquidityPool.sol #58 126 function withdrawAll() external override onlyGovernance {
File: contracts/pool/LiquidityPool.sol #59 130 function setLpToken(address _lpToken) 131 external 132 override 133 onlyRoles2(Roles.GOVERNANCE, Roles.POOL_FACTORY) 134 returns (bool)
File: contracts/pool/LiquidityPool.sol #60 178 function prepareNewRequiredReserves(uint256 _newRatio) external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #61 198 function resetRequiredReserves() external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #62 207 function prepareNewReserveDeviation(uint256 newRatio) external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #63 227 function resetNewReserveDeviation() external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #64 236 function prepareNewMinWithdrawalFee(uint256 newFee) external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #65 256 function resetNewMinWithdrawalFee() external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #66 265 function prepareNewMaxWithdrawalFee(uint256 newFee) external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #67 285 function resetNewMaxWithdrawalFee() external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #68 294 function prepareNewWithdrawalFeeDecreasePeriod(uint256 newPeriod) 295 external 296 onlyGovernance 297 returns (bool)
File: contracts/pool/LiquidityPool.sol #69 315 function resetNewWithdrawalFeeDecreasePeriod() external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #70 325 function setStaker() 326 external 327 override 328 onlyRoles2(Roles.GOVERNANCE, Roles.POOL_FACTORY) 329 returns (bool)
File: contracts/pool/LiquidityPool.sol #71 345 function prepareNewVault(address _vault) external override onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #72 369 function resetNewVault() external onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #73 386 function uncap() external override onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #74 398 function updateDepositCap(uint256 _depositCap) external override onlyGovernance returns (bool) {
File: contracts/pool/LiquidityPool.sol #75 410 function rebalanceVault() external onlyGovernance {
File: contracts/pool/PoolFactory.sol #76 90 function addPoolImplementation(bytes32 name, address implementation) 91 external 92 onlyGovernance 93 returns (bool)
File: contracts/pool/PoolFactory.sol #77 103 function addLpTokenImplementation(bytes32 name, address implementation) 104 external 105 onlyGovernance 106 returns (bool)
File: contracts/pool/PoolFactory.sol #78 116 function addVaultImplementation(bytes32 name, address implementation) 117 external 118 onlyGovernance 119 returns (bool)
File: contracts/pool/PoolFactory.sol #79 129 function addStakerVaultImplementation(bytes32 name, address implementation) 130 external 131 onlyGovernance 132 returns (bool)
File: contracts/pool/PoolFactory.sol #80 148 function deployPool( 149 string calldata poolName, 150 uint256 depositCap, 151 address underlying, 152 LpTokenArgs calldata lpTokenArgs, 153 VaultArgs calldata vaultArgs, 154 ImplementationNames calldata implementationNames 155 ) external onlyGovernance returns (Addresses memory addrs) {
File: contracts/StakerVault.sol #81 69 function initializeLpGauge(address _lpGauge) external override onlyGovernance returns (bool) {
File: contracts/StakerVault.sol #82 76 function prepareLpGauge(address _lpGauge) external override onlyGovernance returns (bool) {
File: contracts/StakerVault.sol #83 81 function executeLpGauge() external override onlyGovernance returns (bool) {
File: contracts/strategies/BkdTriHopCvx.sol #84 82 function setHopImbalanceToleranceIn(uint256 _hopImbalanceToleranceIn) 83 external 84 onlyGovernance 85 returns (bool)
File: contracts/strategies/BkdTriHopCvx.sol #85 98 function setHopImbalanceToleranceOut(uint256 _hopImbalanceToleranceOut) 99 external 100 onlyGovernance 101 returns (bool)
File: contracts/strategies/BkdTriHopCvx.sol #86 115 function changeConvexPool( 116 uint256 convexPid_, 117 address curvePool_, 118 uint256 curveIndex_ 119 ) external onlyGovernance {
File: contracts/strategies/ConvexStrategyBase.sol #87 116 function deposit() external payable override onlyVault returns (bool) {
File: contracts/strategies/ConvexStrategyBase.sol #88 130 function withdraw(uint256 amount_) external override onlyVault returns (bool) {
File: contracts/strategies/ConvexStrategyBase.sol #89 159 function harvest() external override onlyVault returns (uint256) {
File: contracts/strategies/ConvexStrategyBase.sol #90 167 function shutdown() external override onlyVault returns (bool) {
File: contracts/strategies/ConvexStrategyBase.sol #91 181 function setCommunityReserve(address _communityReserve) external onlyGovernance returns (bool) {
File: contracts/strategies/ConvexStrategyBase.sol #92 192 function setCrvCommunityReserveShare(uint256 crvCommunityReserveShare_) 193 external 194 onlyGovernance 195 returns (bool)
File: contracts/strategies/ConvexStrategyBase.sol #93 209 function setCvxCommunityReserveShare(uint256 cvxCommunityReserveShare_) 210 external 211 onlyGovernance 212 returns (bool)
File: contracts/strategies/ConvexStrategyBase.sol #94 227 function setImbalanceToleranceIn(uint256 imbalanceToleranceIn_) 228 external 229 onlyGovernance 230 returns (bool)
File: contracts/strategies/ConvexStrategyBase.sol #95 243 function setImbalanceToleranceOut(uint256 imbalanceToleranceOut_) 244 external 245 onlyGovernance 246 returns (bool)
File: contracts/strategies/ConvexStrategyBase.sol #96 272 function addRewardToken(address token_) external onlyGovernance returns (bool) {
File: contracts/strategies/ConvexStrategyBase.sol #97 290 function removeRewardToken(address token_) external onlyGovernance returns (bool) {
File: contracts/strategies/StrategySwapper.sol #98 109 function setSlippageTolerance(uint256 slippageTolerance_) external override onlyGovernance {
File: contracts/strategies/StrategySwapper.sol #99 122 function setCurvePool(address token_, address curvePool_) external override onlyGovernance {
File: contracts/strategies/StrategySwapper.sol #100 134 function setSwapViaUniswap(address token_, bool swapViaUniswap_) 135 external 136 override 137 onlyGovernance
File: contracts/utils/Pausable.sol #101 23 function pause() external onlyAuthorizedToPause returns (bool) {
File: contracts/utils/Pausable.sol #102 32 function unpause() external onlyAuthorizedToPause returns (bool) {
File: contracts/vault/VaultReserve.sol #103 43 function deposit(address token, uint256 amount) 44 external 45 payable 46 override 47 onlyVault 48 returns (bool)
File: contracts/vault/VaultReserve.sol #104 72 function withdraw(address token, uint256 amount) external override onlyVault returns (bool) {
File: contracts/vault/Vault.sol #105 105 function deposit() external payable override onlyPoolOrMaintenance {
File: contracts/vault/Vault.sol #106 118 function withdraw(uint256 amount) external override onlyPoolOrGovernance returns (bool) {
File: contracts/vault/Vault.sol #107 152 function withdrawAll() external override onlyPoolOrGovernance {
File: contracts/vault/Vault.sol #108 163 function withdrawFromReserve(uint256 amount) external override onlyGovernance {
File: contracts/vault/Vault.sol #109 175 function activateStrategy() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #110 183 function deactivateStrategy() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #111 193 function initializeStrategy(address strategy_) external override onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #112 207 function prepareNewStrategy(address newStrategy) 208 external 209 override 210 onlyGovernance 211 returns (bool)
File: contracts/vault/Vault.sol #113 250 function resetNewStrategy() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #114 259 function preparePerformanceFee(uint256 newPerformanceFee) 260 external 261 onlyGovernance 262 returns (bool)
File: contracts/vault/Vault.sol #115 277 function resetPerformanceFee() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #116 286 function prepareStrategistFee(uint256 newStrategistFee) external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #117 302 function resetStrategistFee() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #118 311 function prepareDebtLimit(uint256 newDebtLimit) external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #119 329 function resetDebtLimit() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #120 338 function prepareTargetAllocation(uint256 newTargetAllocation) 339 external 340 onlyGovernance 341 returns (bool)
File: contracts/vault/Vault.sol #121 357 function resetTargetAllocation() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #122 366 function prepareReserveFee(uint256 newReserveFee) external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #123 382 function resetReserveFee() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #124 391 function prepareBound(uint256 newBound) external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #125 407 function resetBound() external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #126 416 function withdrawFromStrategy(uint256 amount) external onlyGovernance returns (bool) {
File: contracts/vault/Vault.sol #127 499 function withdrawAllFromStrategy() public onlyPoolOrGovernance returns (bool) {
File: contracts/vault/Vault.sol #128 509 function harvest() public onlyPoolOrMaintenance returns (bool) {
#0 - liveactionllama
2022-04-28T00:47:38Z
Warden created this issue as a placeholder, because their submission was too large for the contest form. They then emailed their md file to our team and we received at 22:49 UTC on 04/27/2022 (prior to contest close). I've updated this issue with their md file content.
#1 - liveactionllama
2022-05-06T22:23:45Z
Note: my original copy/paste did not capture all of the warden's content. I've updated this issue to now contain the entirety from the original submission. I've also notified the sponsor and judge.
#2 - gzeoneth
2022-05-08T20:51:40Z
This report covered most of the gas optimization but is quite difficult to consume due to its length and missing an index. Probably don't need to include all the code snippet in the report.