Platform: Code4rena
Start Date: 08/05/2023
Pot Size: $90,500 USDC
Total HM: 17
Participants: 102
Period: 7 days
Judge: 0xean
Total Solo HM: 4
Id: 236
League: ETH
Rank: 102/102
Findings: 1
Award: $44.94
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: JCN
Also found by: 0xAce, 0xSmartContract, Aymen0909, K42, Rageur, Raihan, ReyAdmirado, SAAJ, SM3_SS, Sathish9098, Team_Rocket, Udsen, c3phas, codeslide, descharre, fatherOfBlocks, hunter_w3b, j4ld1na, lllu_23, matrix_0wl, naman1778, petrichor, pontifex, rapha, souilos, wahedtalash77
44.9387 USDC - $44.94
Issues | Instances | |
---|---|---|
G-01 | Use assembly to check for address(0) . Save Gas. | 32 |
G-02 | It is not necessary to declare. No need to read amountLeft . | 1 |
G-03 | Consider using Assembly sometimes for Loops and If statements. Save gas. | 1 |
G-04 | When possible, use assembly instead of unchecked{++i} . | 37 |
G-05 | Consider use assembly for math (add, sub, mul, div). | 42 |
address(0)
. Save Gas.There are 32 instances:
Example:
function ownerNotZero(address _addr) public pure { require(_addr != address(0), "zero address)"); }
Gas: 258
function assemblyOwnerNotZero(address _addr) public pure { assembly { if iszero(_addr) { mstore(0x00, "zero address") revert(0x00, 0x20) } } }
Gas: 252
require(poolRegistry_ != address(0), "invalid pool registry address");
require(address(newOracle) != address(0), "invalid price oracle address");
require(admin_ != address(0), "invalid admin address");
require(spender != address(0), "invalid spender address");
require(minter != address(0), "invalid minter address");
require(spender != address(0), "invalid spender address");
require(spender != address(0), "invalid spender address");
if (shortfall_ == address(0)) { revert ZeroAddressNotAllowed(); }
if (protocolShareReserve_ == address(0)) { revert ZeroAddressNotAllowed(); }
require(convertibleBaseAsset_ != address(0), "invalid base asset address");
require(_poolRegistry != address(0), "invalid address");
Pool/PoolRegistry.sol#L225-L226
require(beaconAddress != address(0), "PoolRegistry: Invalid Comptroller beacon address."); require(priceOracle != address(0), "PoolRegistry: Invalid PriceOracle address.");
Pool/PoolRegistry.sol#L257-L260
require(input.comptroller != address(0), "PoolRegistry: Invalid comptroller address"); require(input.asset != address(0), "PoolRegistry: Invalid asset address"); require(input.beaconAddress != address(0), "PoolRegistry: Invalid beacon address"); require(input.vTokenReceiver != address(0), "PoolRegistry: Invalid vTokenReceiver address");
require(venusPool.creator == address(0), "PoolRegistry: Pool already exists in the directory.");
Pool/PoolRegistry.sol#L431-L433
if (protocolShareReserve_ == address(0)) { revert ZeroAddressNotAllowed(); }
require(pancakeSwapRouter_ != address(0), "Risk Fund: Pancake swap address invalid"); require(convertibleBaseAsset_ != address(0), "Risk Fund: Base asset address invalid");
require(_poolRegistry != address(0), "Risk Fund: Pool registry address invalid");
require(shortfallContractAddress_ != address(0), "Risk Fund: Shortfall contract address invalid");
require(pancakeSwapRouter_ != address(0), "Risk Fund: PancakeSwap address invalid");
require(poolRegistry != address(0), "Risk fund: Invalid pool registry.");
RiskFund/ProtocolShareReserve.sol#L40-L41
require(_protocolIncome != address(0), "ProtocolShareReserve: Protocol Income address invalid"); require(_riskFund != address(0), "ProtocolShareReserve: Risk Fund address invalid");
RiskFund/ProtocolShareReserve.sol#L54
require(_poolRegistry != address(0), "ProtocolShareReserve: Pool registry address invalid");
RiskFund/ProtocolShareReserve.sol#L71
require(asset != address(0), "ProtocolShareReserve: Asset address invalid");
RiskFund/ReserveHelpers.sol#L52-L53
require(asset != address(0), "ReserveHelpers: Asset address invalid"); require(poolRegistry != address(0), "ReserveHelpers: Pool Registry address is not set");
Proxy/UpgradeableBeacon.sol#L8
require(implementation_ != address(0), "Invalid implementation address");
Recommended Mitigations Steps:
amountLeft
.The an instance:
Rewards/RewardsDistributor.sol#L182-L183
uint256 amountLeft = _grantRewardToken(recipient, amount); require(amountLeft == 0, "insufficient rewardToken for grant");
Recommended Mitigations Steps:
change to:
require(_grantRewardToken(recipient, amount) == 0, 'insufficient rewardToken for grant');
Loops
and If
statements. Save gas.There an instance:
Example:
function howManyEvens(uint256 startNum, uint256 endNum) external pure returns(uint256) { // the value we will return uint256 ans; assembly { // syntax for for loop for { let i := startNum } lt( i, add(endNum, 1) ) { i := add(i,1) } { // if i == 0 skip this iteration if iszero(i) { continue } // checks if i % 2 == 0 // we could of used iszero, but I wanted to show you eq() if eq( mod( i, 2 ), 0 ) { ans := add(ans, 1) } } } return ans; }
uint256 assetIndex = len; for (uint256 i; i < len; ++i) { if (userAssetList[i] == vToken) { assetIndex = i; break; } }
Recommended Mitigations Steps:
unchecked{++i}
.You can also use unchecked{++i;}
for even more gas savings but this will not check to see if i
overflows. For best gas savings, use inline assembly, however this limits the functionality you can achieve.
Example:
//loop with unchecked{++i} function uncheckedPlusPlusI() public pure { uint256 j = 0; for (uint256 i; i < 10; ) { j++; unchecked { ++i; } } }
Gas: 1329
//loop with inline assembly function inlineAssemblyLoop() public pure { assembly { let j := 0 for { let i := 0 } lt(i, 10) { i := add(i, 0x01) } { j := add(j, 0x01) } } }
Gas: 709
Recommended Mitigations Steps:
Use assembly for math instead of Solidity. You can check for overflow/underflow in assembly to ensure safety.
There are 42 instances:
Example Addition:
//addition in Solidity function addTest(uint256 a, uint256 b) public pure { uint256 c = a + b; }
Gas: 303
//addition in assembly function addAssemblyTest(uint256 a, uint256 b) public pure { assembly { let c := add(a, b) if lt(c, a) { mstore(0x00, "overflow") revert(0x00, 0x20) } } }
Gas: 263
ExponentialNoError.sol#L81-L83
function add_(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; }
Example Subtraction:
//subtraction in Solidity function subTest(uint256 a, uint256 b) public pure { uint256 c = a - b; }
Gas: 300
//subtraction in assembly function subAssemblyTest(uint256 a, uint256 b) public pure { assembly { let c := sub(a, b) if gt(c, a) { mstore(0x00, "underflow") revert(0x00, 0x20) } } }
Gas: 263
ExponentialNoError.sol#L93-L95
function sub_(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; }
Example Multiplication:
//multiplication in Solidity function mulTest(uint256 a, uint256 b) public pure { uint256 c = a * b; }
Gas: 325
//multiplication in assembly function mulAssemblyTest(uint256 a, uint256 b) public pure { assembly { let c := mul(a, b) if lt(c, a) { mstore(0x00, "overflow") revert(0x00, 0x20) } } }
Gas: 265
ExponentialNoError.sol#L121-L123
function mul_(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; }
Example Division:
//division in Solidity function divTest(uint256 a, uint256 b) public pure { uint256 c = a * b; }
Gas: 325
//division in assembly function divAssemblyTest(uint256 a, uint256 b) public pure { assembly { let c := div(a, b) if gt(c, a) { mstore(0x00, "underflow") revert(0x00, 0x20) } } }
Gas: 265
ExponentialNoError.sol#L149-L151
function div_(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; }
uint256 oneMinusReserveFactor = BASE - reserveFactorMantissa;
uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / BASE;
return (borrows * BASE) / (cash + borrows - reserves);
BaseJumpRateModelV2.sol#L157-L159
baseRatePerBlock = baseRatePerYear / blocksPerYear; multiplierPerBlock = (multiplierPerYear * BASE) / (blocksPerYear * kink_); jumpMultiplierPerBlock = jumpMultiplierPerYear / blocksPerYear;
return (util * multiplierPerBlock) / BASE + baseRatePerBlock;
uint256 normalRate = ((kink * multiplierPerBlock) / BASE) + baseRatePerBlock;
excessUtil = util - kink;
return (excessUtil * jumpMultiplierPerBlock) / BASE + normalRate;
WhitePaperInterestRateModel.sol#L37-L38
baseRatePerBlock = baseRatePerYear / blocksPerYear; multiplierPerBlock = multiplierPerYear / blocksPerYear;
WhitePaperInterestRateModel.sol#L56
return (ur * multiplierPerBlock) / BASE + baseRatePerBlock;
WhitePaperInterestRateModel.sol#L73
uint256 oneMinusReserveFactor = BASE - reserveFactorMantissa;
WhitePaperInterestRateModel.sol#L75
uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / BASE;
WhitePaperInterestRateModel.sol#L96
return (borrows * BASE) / (cash + borrows - reserves);
RiskFund/ReserveHelpers.sol#L64
balanceDifference = currentBalance - assetReserve;
riskFundBidAmount = (auction.seizedRiskFund * auction.highestBidBps) / MAX_BPS;
totalSupply = totalSupply + mintTokens;
totalSupply = totalSupply - redeemTokens;
uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount; uint256 totalBorrowsNew = totalBorrows + borrowAmount;
uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount; uint256 totalBorrowsNew = totalBorrows - actualRepayAmount;
uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;
uint256 totalReservesNew = totalReserves + protocolSeizeAmount;
totalSupply = totalSupply - protocolSeizeTokens;
totalReservesNew = totalReserves + actualAddAmount;
return balanceAfter - balanceBefore;
uint256 allowanceNew = startingAllowance - tokens;
uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex; return principalTimesIndex / borrowSnapshot.interestIndex;
uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows + badDebt - totalReserves; uint256 exchangeRate = (cashPlusBorrowsMinusReserves * expScale) / _totalSupply;
uint256 nextTotalBorrows = totalBorrows + borrowAmount;
uint256 borrowPlusEffects = snapshot.borrows + snapshot.effects;
snapshot.liquidity = snapshot.weightedCollateral - borrowPlusEffects;
snapshot.shortfall = borrowPlusEffects - snapshot.weightedCollateral;
Recommended Mitigations Steps:
#0 - c4-judge
2023-05-18T17:42:01Z
0xean marked the issue as grade-b