Platform: Code4rena
Start Date: 03/05/2022
Pot Size: $50,000 USDC
Total HM: 4
Participants: 46
Period: 5 days
Judge: gzeon
Total Solo HM: 2
Id: 117
League: ETH
Rank: 5/46
Findings: 3
Award: $1,029.73
🌟 Selected for report: 0
🚀 Solo Findings: 0
Judge has assessed an item in Issue #26 as Medium risk. The relevant finding follows:
#0 - gzeoneth
2022-05-29T14:05:03Z
Duplicate of #1
🌟 Selected for report: BowTiedWardens
Also found by: 0x1337, 0x1f8b, 0x4non, 0xDjango, David_, Funen, GimelSec, IllIllI, Picodes, TerrierLover, WatchPug, bobi, cryptphi, csanuragjain, delfin454000, dirk_y, ellahi, fatherOfBlocks, hyh, ilan, jayjonah8, kebabsec, leastwood, oyc_109, robee, samruna, simon135, sorrynotsorry, throttle
543.0279 USDC - $543.03
latestAnswer()
is deprecatedUse latestRoundData()
instead so that you can tell whether the answer is stale or not. The function returns zero if it is unable to fetch data, which may be the case if ChainLink stops supporting this API. The API and its deprecation message no longer even appear on the ChainLink website.
File: /contracts/PriceOracleImplementation.sol #1 29 int256 usdcPrice = ChainlinkFeed(0x986b5E1e1755e3C2440e960477f25201B0a8bbD4).latestAnswer();
address(0x0)
when assigning values to address
state variablesFile: /contracts/Oracles/CNftPriceOracle.sol #1 48 admin = _admin;
File: /contracts/Oracles/CNftPriceOracle.sol #2 50 uniswapV2Factory = _uniswapV2Factory;
File: /contracts/Oracles/CNftPriceOracle.sol #3 51 baseToken = _baseToken;
File: /contracts/Oracles/CNftPriceOracle.sol #4 55 admin = newAdmin;
File: /contracts/PriceOracleImplementation.sol #5 13 cEtherAddress = _cEtherAddress;
__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/CNft.sol #1 16 contract CNft is CNftInterface, ERC1155Enumerable, IERC1155Receiver, IERC721Receiver, ReentrancyGuardUpgradeable, OwnableUpgradeable {
require()
should be used instead of assert()
Prior to solidity version 0.8.0, hitting an assert()
consumes the remainder of the transaction's available gas rather than returning it, as require()
/revert()
do
File: /contracts/Comptroller.sol #1 207 assert(assetIndex < len);
File: /contracts/Comptroller.sol #2 333 assert(markets[cToken].accountMembership[borrower]);
override
function arguments that are unused should have the variable name removed or commented out to avoid compiler warningsFile: /contracts/CNft.sol #1 215 address from,
File: /contracts/CNft.sol #2 216 uint256 tokenId,
File: /contracts/CNft.sol #3 217 bytes calldata data
File: /contracts/CNft.sol #4 224 address from,
File: /contracts/CNft.sol #5 225 uint256 id,
File: /contracts/CNft.sol #6 226 uint256 value,
File: /contracts/CNft.sol #7 227 bytes calldata data
File: /contracts/CNft.sol #8 234 address from,
File: /contracts/CNft.sol #9 235 uint256[] calldata ids,
File: /contracts/CNft.sol #10 236 uint256[] calldata values,
File: /contracts/CNft.sol #11 237 bytes calldata data
require()
/revert()
statements should have descriptive reason stringsFile: /contracts/CEther.sol #1 148 require(err == MathError.NO_ERROR);
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/Comptroller.sol #1 115 function enterMarkets(address[] memory cTokens) public returns (uint[] memory) {
File: /contracts/Comptroller.sol #2 533 function getAccountLiquidity(address account) public view returns (uint, uint, uint) {
File: /contracts/Comptroller.sol #3 559 function getHypotheticalAccountLiquidity( 560 address account, 561 address cAssetModify, 562 uint redeemTokens, 563 uint borrowAmount) public view returns (uint, uint, uint) {
File: /contracts/Comptroller.sol #4 741 function _setPriceOracle(PriceOracle newOracle) public returns (uint) {
File: /contracts/Comptroller.sol #5 764 function _setNftPriceOracle(NftPriceOracle newOracle) public returns (uint) {
File: /contracts/Comptroller.sol #6 977 function _setPauseGuardian(address newPauseGuardian) public returns (uint) {
File: /contracts/Comptroller.sol #7 994 function _setMintPaused(address cAsset, bool state) public returns (bool) {
File: /contracts/Comptroller.sol #8 1008 function _setBorrowPaused(CToken cToken, bool state) public returns (bool) {
File: /contracts/Comptroller.sol #9 1018 function _setTransferPaused(bool state) public returns (bool) {
File: /contracts/Comptroller.sol #10 1027 function _setSeizePaused(bool state) public returns (bool) {
File: /contracts/Comptroller.sol #11 1036 function _become(Unitroller unitroller) public {
File: /contracts/Comptroller.sol #12 1270 function _grantComp(address recipient, uint amount) public {
File: /contracts/Comptroller.sol #13 1282 function _setCompSpeed(CToken cToken, uint compSpeed) public {
File: /contracts/Comptroller.sol #14 1292 function _setContributorCompSpeed(address contributor, uint compSpeed) public {
File: /contracts/Comptroller.sol #15 1313 function getAllMarkets() public view returns (CToken[] memory) {
File: /contracts/CToken.sol #16 1452 function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {
constant
s should be defined rather than using magic numbersFile: /contracts/CEther.sol #1 175 bytes memory fullMessage = new bytes(bytes(message).length + 5);
File: /contracts/CEther.sol #2 182 fullMessage[i+0] = byte(uint8(32));
File: /contracts/CEther.sol #3 183 fullMessage[i+1] = byte(uint8(40));
File: /contracts/CEther.sol #4 184 fullMessage[i+2] = byte(uint8(48 + ( errCode / 10 )));
File: /contracts/CEther.sol #5 185 fullMessage[i+3] = byte(uint8(48 + ( errCode % 10 )));
File: /contracts/CEther.sol #6 185 fullMessage[i+3] = byte(uint8(48 + ( errCode % 10 )));
File: /contracts/CEther.sol #7 186 fullMessage[i+4] = byte(uint8(41));
File: /contracts/CEther.sol #8 186 fullMessage[i+4] = byte(uint8(41));
File: /contracts/Comptroller.sol #9 1326 cToken.reserveFactorMantissa() == 1e18
File: /contracts/Oracles/CNftPriceOracle.sol #10 99 return FullMath.mulDiv(pricePerToken, 10**18 - mintFee, 10**18);
File: /contracts/Oracles/CNftPriceOracle.sol #11 99 return FullMath.mulDiv(pricePerToken, 10**18 - mintFee, 10**18);
File: /contracts/Oracles/UniswapV2PriceOracle.sol #12 64 uint32 timeElapsed = uint32(block.timestamp % (2**32)) - blockTimestampLast;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #13 71 px0Cumulative += uint256((uint224(reserve1) << 112) / reserve0) * timeElapsed;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #14 72 px1Cumulative += uint256((uint224(reserve0) << 112) / reserve1) * timeElapsed;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #15 88 uint32 timeElapsed = uint32(block.timestamp % (2**32)) - blockTimestampLast;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #16 95 px0Cumulative += uint256((uint224(reserve1) << 112) / reserve0) * timeElapsed;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #17 112 uint32 timeElapsed = uint32(block.timestamp % (2**32)) - blockTimestampLast;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #18 119 px1Cumulative += uint256((uint224(reserve0) << 112) / reserve1) * timeElapsed;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #19 177 return FullMath.mulDiv(token < baseToken ? price0(pair) : price1(pair), baseUnit, 2**112);
File: /contracts/PriceOracleImplementation.sol #20 25 return 1e18;
File: /contracts/PriceOracleImplementation.sol #21 29 int256 usdcPrice = ChainlinkFeed(0x986b5E1e1755e3C2440e960477f25201B0a8bbD4).latestAnswer();
File: /contracts/PriceOracleImplementation.sol #22 35 uint256 result = uint256(usdcPrice) * 1e12;
File: /contracts/PriceOracleImplementation.sol #23 36 if (result / uint256(usdcPrice) != 1e12) {
Use a solidity version of at least 0.8.13 to get the ability to use using for
with a list of free functions
File: /contracts/ERC1155Enumerable.sol #1 2 pragma solidity ^0.8.0;
1e18
) rather than exponentiation (e.g. 10**18
)File: /contracts/Oracles/CNftPriceOracle.sol #1 99 return FullMath.mulDiv(pricePerToken, 10**18 - mintFee, 10**18);
File: /contracts/Oracles/CNftPriceOracle.sol #2 99 return FullMath.mulDiv(pricePerToken, 10**18 - mintFee, 10**18);
File: /contracts/CErc20.sol #1 1 pragma solidity ^0.5.16;
File: /contracts/CEther.sol #2 1 pragma solidity ^0.5.16;
File: /contracts/CNft.sol #3 2 pragma solidity ^0.8.0;
File: /contracts/Comptroller.sol #4 1 pragma solidity ^0.5.16;
File: /contracts/CToken.sol #5 1 pragma solidity ^0.5.16;
File: /contracts/Oracles/CNftPriceOracle.sol #6 2 pragma solidity ^0.8.0;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #7 2 pragma solidity ^0.8.0;
File: /contracts/PriceOracleImplementation.sol #8 1 pragma solidity ^0.5.16;
File: /contracts/CErc20.sol #1 143 * @param addAmount The amount fo underlying token to add as reserves
File: /contracts/CNft.sol #2 106 // We call the internal function instad of the public one because in liquidation, we
File: /contracts/Comptroller.sol #3 696 * @dev Used in liquidation (called in cToken.liquidateBorrowFreshNft)
liquidateBorrowFreshNft https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L696
File: /contracts/CToken.sol #4 839 * @param repayAmount the amount of undelrying tokens being returned
File: /contracts/CToken.sol #5 1374 /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */
File: /contracts/CToken.sol #6 1514 * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.
File: /contracts/PriceOracleImplementation.sol #7 34 // Checck for overflow.
File: /contracts/CErc20.sol #1 0 pragma solidity ^0.5.16;
File: /contracts/CEther.sol #2 0 pragma solidity ^0.5.16;
File: /contracts/Comptroller.sol #3 0 pragma solidity ^0.5.16;
File: /contracts/CToken.sol #4 0 pragma solidity ^0.5.16;
File: /contracts/PriceOracleImplementation.sol #5 0 pragma solidity ^0.5.16;
File: /contracts/CNft.sol #1 272 * @param data Encoded data to send 273 */ 274 function call( 275 address to, 276 uint256 value, 277 bytes calldata data 278 ) external payable nonReentrant onlyOwner returns (bool success) {
Missing: @return
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/CNft.sol#L272-L278
File: /contracts/Comptroller.sol #2 401 * @param repayAmount The amount of underlying being repaid 402 */ 403 function liquidateBorrowAllowed( 404 address cTokenBorrowed, 405 address cTokenCollateral, 406 address liquidator, 407 address borrower, 408 uint repayAmount) external returns (uint) {
Missing: @return
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L401-L408
File: /contracts/Comptroller.sol #3 447 * @param seizeTokens The number of collateral tokens to seize 448 */ 449 function seizeAllowed( 450 address cTokenCollateral, 451 address cTokenBorrowed, 452 address liquidator, 453 address borrower, 454 uint seizeTokens) external returns (uint) {
Missing: @return
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L447-L454
File: /contracts/Comptroller.sol #4 527 /** 528 * @notice Determine the current account liquidity wrt collateral requirements 529 * @return (possible error code (semi-opaque), 530 account liquidity in excess of collateral requirements, 531 * account shortfall below collateral requirements) 532 */ 533 function getAccountLiquidity(address account) public view returns (uint, uint, uint) {
Missing: @param account
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L527-L533
File: /contracts/Comptroller.sol #5 539 /** 540 * @notice Determine the current account liquidity wrt collateral requirements 541 * @return (possible error code, 542 account liquidity in excess of collateral requirements, 543 * account shortfall below collateral requirements) 544 */ 545 function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {
Missing: @param account
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L539-L545
File: /contracts/Comptroller.sol #6 694 /** 695 * @notice Calculate number of cNFT tokens to seize given an underlying amount 696 * @dev Used in liquidation (called in cToken.liquidateBorrowFreshNft) 697 * @param cTokenBorrowed The address of the borrowed cToken 698 * @param actualRepayAmount The amount of cTokenBorrowed underlying to convert into NFTs 699 * @return (errorCode, number of cNft tokens to be seized in a liquidation) 700 */ 701 function liquidateCalculateSeizeNfts(address cTokenBorrowed, address cNftCollateral, uint actualRepayAmount) external view returns (uint, uint) {
Missing: @param cNftCollateral
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L694-L701
File: /contracts/Comptroller.sol #7 736 /** 737 * @notice Sets a new price oracle for the comptroller 738 * @dev Admin function to set a new price oracle 739 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 740 */ 741 function _setPriceOracle(PriceOracle newOracle) public returns (uint) {
Missing: @param newOracle
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L736-L741
File: /contracts/Comptroller.sol #8 759 /** 760 * @notice Sets a new price oracle for the comptroller 761 * @dev Admin function to set a new price oracle 762 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 763 */ 764 function _setNftPriceOracle(NftPriceOracle newOracle) public returns (uint) {
Missing: @param newOracle
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L759-L764
File: /contracts/Comptroller.sol #9 1111 /** 1112 * @notice Accrue COMP to the market by updating the borrow index 1113 * @param cToken The market whose borrow index to update 1114 */ 1115 function updateCompBorrowIndex(address cToken, Exp memory marketBorrowIndex) internal {
Missing: @param marketBorrowIndex
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L1111-L1115
File: /contracts/Comptroller.sol #10 1157 /** 1158 * @notice Calculate COMP accrued by a borrower and possibly transfer it to them 1159 * @dev Borrowers will not begin to accrue until after the first interaction with the protocol. 1160 * @param cToken The market in which the borrower is interacting 1161 * @param borrower The address of the borrower to distribute COMP to 1162 */ 1163 function distributeBorrowerComp(address cToken, address borrower, Exp memory marketBorrowIndex) internal {
Missing: @param marketBorrowIndex
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L1157-L1163
File: /contracts/Comptroller.sol #11 1320 * @param cToken The market to check if deprecated 1321 */ 1322 function isDeprecated(CToken cToken) public view returns (bool) {
Missing: @return
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Comptroller.sol#L1320-L1322
File: /contracts/CToken.sol #12 726 /** 727 * @notice Users borrow assets from the protocol to their own address 728 * @param borrowAmount The amount of the underlying asset to borrow 729 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 730 */ 731 function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
Missing: @param borrower
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/CToken.sol#L726-L731
File: /contracts/CToken.sol #13 1251 /** 1252 * @notice Sets a new comptroller for the market 1253 * @dev Admin function to set a new comptroller 1254 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 1255 */ 1256 function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) {
Missing: @param newComptroller
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/CToken.sol#L1251-L1256
File: /contracts/CToken.sol #14 1275 /** 1276 * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh 1277 * @dev Admin function to accrue interest and set a new reserve factor 1278 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 1279 */ 1280 function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) {
Missing: @param newReserveFactorMantissa
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/CToken.sol#L1275-L1280
File: /contracts/CToken.sol #15 1290 /** 1291 * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) 1292 * @dev Admin function to set a new reserve factor 1293 * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 1294 */ 1295 function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
Missing: @param newReserveFactorMantissa
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/CToken.sol#L1290-L1295
indexed
fieldsEach event
should use three indexed
fields if there are three or more fields
File: /contracts/Comptroller.sol #1 18 event MarketListed(CToken cToken);
File: /contracts/Comptroller.sol #2 21 event MarketEntered(CToken cToken, address account);
File: /contracts/Comptroller.sol #3 24 event MarketExited(CToken cToken, address account);
File: /contracts/Comptroller.sol #4 27 event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);
File: /contracts/Comptroller.sol #5 30 event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);
File: /contracts/Comptroller.sol #6 33 event NewNftCollateralFactor(uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);
File: /contracts/Comptroller.sol #7 36 event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);
File: /contracts/Comptroller.sol #8 39 event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);
File: /contracts/Comptroller.sol #9 42 event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);
File: /contracts/Comptroller.sol #10 45 event ActionPaused(string action, bool pauseState);
File: /contracts/Comptroller.sol #11 48 event ActionPaused(CToken cToken, string action, bool pauseState);
File: /contracts/Comptroller.sol #12 51 event CompSpeedUpdated(CToken indexed cToken, uint newSpeed);
File: /contracts/Comptroller.sol #13 54 event ContributorCompSpeedUpdated(address indexed contributor, uint newSpeed);
File: /contracts/Comptroller.sol #14 57 event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);
File: /contracts/Comptroller.sol #15 60 event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);
File: /contracts/Comptroller.sol #16 63 event NewBorrowCap(CToken indexed cToken, uint newBorrowCap);
File: /contracts/Comptroller.sol #17 66 event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian);
File: /contracts/Comptroller.sol #18 69 event CompGranted(address recipient, uint amount);
🌟 Selected for report: BowTiedWardens
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xkatana, Cityscape, Fitraldys, Funen, GimelSec, IllIllI, MaratCerby, Picodes, TerrierLover, Tomio, delfin454000, ellahi, fatherOfBlocks, hansfriese, ilan, joestakey, oyc_109, rfa, robee, samruna, simon135, slywaters, throttle
188.119 USDC - $188.12
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) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot
File: /contracts/Oracles/UniswapV2PriceOracle.sol #1 20 mapping(address => Observation[OBSERVATION_BUFFER_SIZE]) public pairObservations; 21 mapping(address => uint256) public numPairObservations;
immutable
Avoids a Gsset (20000 gas) in the constructor, and replaces each Gwarmacces (100 gas) with a PUSH32
(3 gas)
File: /contracts/PriceOracleImplementation.sol #1 10 address public cEtherAddress;
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, having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
File: /contracts/ERC1155Enumerable.sol #1 49 EnumerableSet.UintSet storage toTokens = _tokensByAccount[to];
_tokensByAccount https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/ERC1155Enumerable.sol#L49
File: /contracts/Oracles/UniswapV2PriceOracle.sol #2 132 lastObservation = pairObservations[pair][(length - 2) % OBSERVATION_BUFFER_SIZE];
pairObservations https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Oracles/UniswapV2PriceOracle.sol#L132
File: /contracts/Oracles/UniswapV2PriceOracle.sol #3 153 lastObservation = pairObservations[pair][(length - 2) % OBSERVATION_BUFFER_SIZE];
pairObservations https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Oracles/UniswapV2PriceOracle.sol#L153
File: /contracts/Oracles/UniswapV2PriceOracle.sol #4 27 (block.timestamp - pairObservations[pair][(numPairObservations[pair] - 1) % OBSERVATION_BUFFER_SIZE].timestamp) <= MIN_TWAP_TIME
numPairObservations https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Oracles/UniswapV2PriceOracle.sol#L27
File: /contracts/Oracles/UniswapV2PriceOracle.sol #5 32 pairObservations[pair][numPairObservations[pair]++ % OBSERVATION_BUFFER_SIZE] = Observation(
numPairObservations https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/Oracles/UniswapV2PriceOracle.sol#L32
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesFile: /contracts/ERC1155Enumerable.sol #1 59 totalSupply += amount;
File: /contracts/ERC1155Enumerable.sol #2 65 totalSupply -= amount;
internal
functions only called once can be inlined to save gasNot inlining costs 20 to 40 gas because of two extra JUMP
instructions and additional stack operations needed for function calls.
File: /contracts/CNft.sol #1 248 function executeCall( 249 address to, 250 uint256 value, 251 bytes memory data, 252 uint256 txGas 253 ) internal returns (bool success) {
File: /contracts/Comptroller.sol #2 545 function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) {
File: /contracts/Comptroller.sol #3 927 function _addMarketInternal(address cToken) internal {
File: /contracts/Comptroller.sol #4 1055 function setCompSpeedInternal(CToken cToken, uint compSpeed) internal {
File: /contracts/Comptroller.sol #5 1139 function distributeSupplierComp(address cToken, address supplier) internal {
File: /contracts/CToken.sol #6 495 function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {
File: /contracts/CToken.sol #7 731 function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
File: /contracts/CToken.sol #8 941 function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal returns (uint, uint) {
File: /contracts/CToken.sol #9 1041 function liquidateBorrowNftFresh(address liquidator, address borrower, uint repayAmount, CNftInterface cNftCollateral, uint[] memory seizeIds, uint[] memory seizeAmounts) internal returns (uint, uint) {
File: /contracts/CToken.sol #10 1295 function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
File: /contracts/CToken.sol #11 1342 function _addReservesFresh(uint addAmount) internal returns (uint, uint) {
File: /contracts/CToken.sol #12 1403 function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #13 24 function update(address pair) internal returns (bool) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #14 52 function cumulativePrices( 53 address pair 54 ) internal view returns (uint256 px0Cumulative, uint256 px1Cumulative) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #15 78 function price0Cumulative(address pair) internal view returns (uint256) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #16 102 function price1Cumulative(address pair) internal view returns (uint256) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #17 126 function price0(address pair) internal view returns (uint256) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #18 147 function price1(address pair) internal view returns (uint256) {
<array>.length
should not be looked up in every loop of a for
-loopThe overheads outlined below are PER LOOP, excluding the first loop
MLOAD
(3 gas)CALLDATALOAD
(3 gas)Caching the length changes each of these to a DUP<N>
(3 gas), and gets rid of the extra DUP<N>
needed to store the stack offset
File: /contracts/CEther.sol #1 178 for (i = 0; i < bytes(message).length; i++) {
File: /contracts/CNft.sol #2 176 for (uint256 i; i < vars.length; ++i) {
File: /contracts/Comptroller.sol #3 591 for (uint i = 0; i < assets.length; i++) {
File: /contracts/Comptroller.sol #4 928 for (uint i = 0; i < allMarkets.length; i ++) {
File: /contracts/Comptroller.sol #5 1223 for (uint i = 0; i < cTokens.length; i++) {
File: /contracts/Comptroller.sol #6 1229 for (uint j = 0; j < holders.length; j++) {
File: /contracts/Comptroller.sol #7 1235 for (uint j = 0; j < holders.length; j++) {
File: /contracts/Comptroller.sol #8 1240 for (uint j = 0; j < holders.length; j++) {
File: /contracts/ERC1155Enumerable.sol #9 51 for (uint256 i; i < ids.length; ++i) {
File: /contracts/Oracles/CNftPriceOracle.sol #10 66 for (uint256 i = 0; i < cNfts.length; ++i) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #11 42 for (uint256 i = 0; i < pairs.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
-loopsThis saves 30-40 gas PER LOOP
File: /contracts/CNft.sol #1 50 for (uint256 i; i < length; ++i) {
File: /contracts/CNft.sol #2 62 for (uint256 i; i < length; ++i) {
File: /contracts/CNft.sol #3 72 for (uint256 i; i < length; ++i) {
File: /contracts/CNft.sol #4 98 for (uint256 i; i < length; ++i) {
File: /contracts/CNft.sol #5 122 for (uint256 i; i < length; ++i) {
File: /contracts/CNft.sol #6 145 for (uint256 i; i < length; ++i) {
File: /contracts/CNft.sol #7 151 for (uint256 i; i < length; ++i) {
File: /contracts/CNft.sol #8 176 for (uint256 i; i < vars.length; ++i) {
File: /contracts/ERC1155Enumerable.sol #9 51 for (uint256 i; i < ids.length; ++i) {
File: /contracts/Oracles/CNftPriceOracle.sol #10 66 for (uint256 i = 0; i < cNfts.length; ++i) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #11 42 for (uint256 i = 0; i < pairs.length; ++i) {
require()
/revert()
strings longer than 32 bytes cost extra gasFile: /contracts/CErc20.sol #1 136 require(address(token) != underlying, "CErc20::sweepToken: can not sweep underlying token");
File: /contracts/CErc20.sol #2 234 require(msg.sender == admin, "only the admin may set the comp-like delegate");
File: /contracts/CNft.sol #3 24 require(_underlying != address(0), "CNFT: Asset should not be address(0)");
File: /contracts/CNft.sol #4 25 require(ComptrollerInterface(_comptroller).isComptroller(), "_comptroller is not a Comptroller contract");
File: /contracts/CNft.sol #5 52 require(amounts[i] == 1, "CNFT: Amounts must be all 1s for non-ERC1155s.");
File: /contracts/CNft.sol #6 69 require(buyPunkSuccess, "CNFT: Calling buyPunk was unsuccessful");
File: /contracts/CNft.sol #7 93 require(borrower != liquidator, "CNFT: Liquidator cannot be borrower");
File: /contracts/CNft.sol #8 100 require(seizeAmounts[i] == 1, "CNFT: Amounts must be all 1s for non-ERC1155s.");
File: /contracts/CNft.sol #9 124 require(amounts[i] == 1, "CNFT: Amounts must be all 1s for non-ERC1155s.");
File: /contracts/CNft.sol #10 148 require(transferPunkSuccess, "CNFT: Calling transferPunk was unsuccessful");
File: /contracts/CNft.sol #11 204 revert("CNFT: Use safeBatchTransferFrom instead");
File: /contracts/CNft.sol #12 208 require(msg.sender == underlying, "CNFT: This contract can only receive the underlying NFT");
File: /contracts/CNft.sol #13 209 require(operator == address(this), "CNFT: Only the CNFT contract can be the operator");
File: /contracts/CNft.sol #14 279 require(to != underlying, "CNFT: Cannot make an arbitrary call to underlying NFT");
File: /contracts/Comptroller.sol #15 171 require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code
File: /contracts/Comptroller.sol #16 420 require(borrowBalance >= repayAmount, "Can not repay more than the total borrow");
File: /contracts/Comptroller.sol #17 702 require(cNftCollateral == address(nftMarket), "cNFT is from the wrong comptroller");
File: /contracts/Comptroller.sol #18 942 require(msg.sender == admin || msg.sender == borrowCapGuardian, "only admin or borrow cap guardian can set borrow caps");
File: /contracts/Comptroller.sol #19 960 require(msg.sender == admin, "only admin can set borrow cap guardian");
File: /contracts/Comptroller.sol #20 995 require(markets[cAsset].isListed, "cannot pause a market that is not listed");
File: /contracts/Comptroller.sol #21 996 require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
File: /contracts/Comptroller.sol #22 1009 require(markets[address(cToken)].isListed, "cannot pause a market that is not listed");
File: /contracts/Comptroller.sol #23 1010 require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
File: /contracts/Comptroller.sol #24 1019 require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
File: /contracts/Comptroller.sol #25 1028 require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
File: /contracts/Comptroller.sol #26 1037 require(msg.sender == unitroller.admin(), "only unitroller admin can change brains");
File: /contracts/Comptroller.sol #27 1338 require(address(nftMarket) == address(0), "nft collateral already initialized");
File: /contracts/Comptroller.sol #28 1339 require(address(cNft) != address(0), "cannot initialize nft market to the 0 address");
File: /contracts/CToken.sol #29 32 require(msg.sender == admin, "only admin may initialize the market");
File: /contracts/CToken.sol #30 33 require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");
File: /contracts/CToken.sol #31 37 require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero.");
File: /contracts/CToken.sol #32 49 require(err == uint(Error.NO_ERROR), "setting interest rate model failed");
File: /contracts/CToken.sol #33 271 require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed");
File: /contracts/CToken.sol #34 328 require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed");
File: /contracts/CToken.sol #35 542 require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED");
File: /contracts/CToken.sol #36 545 require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED");
File: /contracts/CToken.sol #37 609 require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");
File: /contracts/CToken.sol #38 891 require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED");
File: /contracts/CToken.sol #39 894 require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED");
File: /contracts/CToken.sol #40 986 require(amountSeizeError == uint(Error.NO_ERROR), "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");
File: /contracts/CToken.sol #41 1083 require(amountSeizeError == uint(Error.NO_ERROR), "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");
File: /contracts/CToken.sol #42 1093 require(seizeTokens == 0, "LIQUIDATE_SEIZE_INCORRECT_NUM_NFTS");
File: /contracts/CToken.sol #43 1433 require(totalReservesNew <= totalReserves, "reduce reserves unexpected underflow");
File: /contracts/Oracles/CNftPriceOracle.sol #44 62 require( 63 cNfts.length > 0 && cNfts.length == nftxTokens.length, 64 "CNftPriceOracle: `cNfts` and `nftxTokens` must have nonzero, equal lengths." 65 );
File: /contracts/Oracles/CNftPriceOracle.sol #45 68 require( 69 underlyingNftxTokenAddress[underlying] == address(0), 70 "CNftPriceOracle: Cannot overwrite existing address mappings." 71 );
File: /contracts/Oracles/CNftPriceOracle.sol #46 88 require( 89 nftxToken != address(0), 90 "CNftPriceOracle: No NFTX token for cNFT." 91 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #47 66 require( 67 reserve0 > 0 && reserve1 > 0, 68 "UniswapV2PriceOracle: Division by zero." 69 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #48 90 require( 91 reserve0 > 0, 92 "UniswapV2PriceOracle: Division by zero." 93 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #49 114 require( 115 reserve1 > 0, 116 "UniswapV2PriceOracle: Division by zero." 117 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #50 128 require(length > 0, "UniswapV2PriceOracle: No observations.");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #51 131 require(length > 1, "UniswapV2PriceOracle: Only one observation.");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #52 135 require( 136 block.timestamp - lastObservation.timestamp >= MIN_TWAP_TIME, 137 "UniswapV2PriceOracle: Bad TWAP time." 138 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #53 149 require(length > 0, "UniswapV2PriceOracle: No observations.");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #54 152 require(length > 1, "UniswapV2PriceOracle: Only one observation.");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #55 156 require( 157 block.timestamp - lastObservation.timestamp >= MIN_TWAP_TIME, 158 "UniswapV2PriceOracle: Bad TWAP time." 159 );
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/Oracles/CNftPriceOracle.sol #1 12 bool public constant isNftPriceOracle = true;
Use a solidity version of at least 0.8.0 to get overflow protection without SafeMath
Use a solidity version of at least 0.8.2 to get compiler automatic inlining
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require()
strings
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/CErc20.sol #1 1 pragma solidity ^0.5.16;
File: /contracts/CEther.sol #2 1 pragma solidity ^0.5.16;
File: /contracts/Comptroller.sol #3 1 pragma solidity ^0.5.16;
File: /contracts/CToken.sol #4 1 pragma solidity ^0.5.16;
File: /contracts/PriceOracleImplementation.sol #5 1 pragma solidity ^0.5.16;
Use a solidity version of at least 0.8.2 to get compiler automatic inlining
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require()
strings
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/CNft.sol #1 2 pragma solidity ^0.8.0;
File: /contracts/ERC1155Enumerable.sol #2 2 pragma solidity ^0.8.0;
File: /contracts/Oracles/CNftPriceOracle.sol #3 2 pragma solidity ^0.8.0;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #4 2 pragma solidity ^0.8.0;
> 0
costs more gas than != 0
when used on a uint
in a require()
statementThis change saves 6 gas per instance
File: /contracts/Oracles/UniswapV2PriceOracle.sol #1 90 require( 91 reserve0 > 0, 92 "UniswapV2PriceOracle: Division by zero." 93 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #2 114 require( 115 reserve1 > 0, 116 "UniswapV2PriceOracle: Division by zero." 117 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #3 128 require(length > 0, "UniswapV2PriceOracle: No observations.");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #4 149 require(length > 0, "UniswapV2PriceOracle: No observations.");
File: /contracts/CNft.sol #1 49 uint256 totalAmount = 0;
File: /contracts/CNft.sol #2 97 uint256 totalAmount = 0;
File: /contracts/CNft.sol #3 119 uint256 totalAmount = 0;
File: /contracts/Comptroller.sol #4 119 for (uint i = 0; i < len; i++) {
File: /contracts/Comptroller.sol #5 199 for (uint i = 0; i < len; i++) {
File: /contracts/Comptroller.sol #6 591 for (uint i = 0; i < assets.length; i++) {
File: /contracts/Comptroller.sol #7 928 for (uint i = 0; i < allMarkets.length; i ++) {
File: /contracts/Comptroller.sol #8 949 for(uint i = 0; i < numMarkets; i++) {
File: /contracts/Comptroller.sol #9 1223 for (uint i = 0; i < cTokens.length; i++) {
File: /contracts/Comptroller.sol #10 1229 for (uint j = 0; j < holders.length; j++) {
File: /contracts/Comptroller.sol #11 1235 for (uint j = 0; j < holders.length; j++) {
File: /contracts/Comptroller.sol #12 1240 for (uint j = 0; j < holders.length; j++) {
File: /contracts/CToken.sol #13 81 uint startingAllowance = 0;
File: /contracts/Oracles/CNftPriceOracle.sol #14 66 for (uint256 i = 0; i < cNfts.length; ++i) {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #15 41 uint256 numberUpdated = 0;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #16 42 for (uint256 i = 0; i < pairs.length; ++i) {
internal
functions not called by the contract should be removed to save deployment gasIf the functions are required by an interface, the contract should inherit from that interface and use the override
keyword
File: /contracts/CErc20.sol #1 157 function getCashPrior() internal view returns (uint) {
File: /contracts/CErc20.sol #2 171 function doTransferIn(address from, uint amount) internal returns (uint) {
File: /contracts/CErc20.sol #3 207 function doTransferOut(address payable to, uint amount) internal {
File: /contracts/CEther.sol #4 146 function getCashPrior() internal view returns (uint) {
File: /contracts/CEther.sol #5 158 function doTransferIn(address from, uint amount) internal returns (uint) {
File: /contracts/CEther.sol #6 165 function doTransferOut(address payable to, uint amount) internal {
++i
costs less gas than ++i
, especially when it's used in for
-loops (--i
/i--
too)Saves 6 gas PER LOOP
File: /contracts/CEther.sol #1 178 for (i = 0; i < bytes(message).length; i++) {
File: /contracts/Comptroller.sol #2 119 for (uint i = 0; i < len; i++) {
File: /contracts/Comptroller.sol #3 199 for (uint i = 0; i < len; i++) {
File: /contracts/Comptroller.sol #4 591 for (uint i = 0; i < assets.length; i++) {
File: /contracts/Comptroller.sol #5 928 for (uint i = 0; i < allMarkets.length; i ++) {
File: /contracts/Comptroller.sol #6 949 for(uint i = 0; i < numMarkets; i++) {
File: /contracts/Comptroller.sol #7 1223 for (uint i = 0; i < cTokens.length; i++) {
File: /contracts/Comptroller.sol #8 1229 for (uint j = 0; j < holders.length; j++) {
File: /contracts/Comptroller.sol #9 1235 for (uint j = 0; j < holders.length; j++) {
File: /contracts/Comptroller.sol #10 1240 for (uint j = 0; j < holders.length; j++) {
require()
statements that use &&
saves gasSee this issue for an example
File: /contracts/CNft.sol #1 66 require(checkSuccess && nftOwner == msg.sender, "Not the NFT owner");
File: /contracts/Comptroller.sol #2 947 require(numMarkets != 0 && numMarkets == numBorrowCaps, "invalid input");
File: /contracts/CToken.sol #3 33 require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");
File: /contracts/Oracles/CNftPriceOracle.sol #4 62 require( 63 cNfts.length > 0 && cNfts.length == nftxTokens.length, 64 "CNftPriceOracle: `cNfts` and `nftxTokens` must have nonzero, equal lengths." 65 );
File: /contracts/Oracles/UniswapV2PriceOracle.sol #5 66 require( 67 reserve0 > 0 && reserve1 > 0, 68 "UniswapV2PriceOracle: Division by zero." 69 );
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/CErc20.sol #1 31 uint8 decimals_) public {
File: /contracts/CEther.sol #2 26 uint8 decimals_,
File: /contracts/Comptroller.sol #3 72 uint224 public constant compInitialIndex = 1e36;
File: /contracts/CToken.sol #4 31 uint8 decimals_) public {
File: /contracts/Oracles/UniswapV2PriceOracle.sol #5 59 uint112 reserve0,
File: /contracts/Oracles/UniswapV2PriceOracle.sol #6 60 uint112 reserve1,
File: /contracts/Oracles/UniswapV2PriceOracle.sol #7 61 uint32 blockTimestampLast
File: /contracts/Oracles/UniswapV2PriceOracle.sol #8 64 uint32 timeElapsed = uint32(block.timestamp % (2**32)) - blockTimestampLast;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #9 82 uint112 reserve0,
File: /contracts/Oracles/UniswapV2PriceOracle.sol #10 83 uint112 reserve1,
File: /contracts/Oracles/UniswapV2PriceOracle.sol #11 84 uint32 blockTimestampLast
File: /contracts/Oracles/UniswapV2PriceOracle.sol #12 88 uint32 timeElapsed = uint32(block.timestamp % (2**32)) - blockTimestampLast;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #13 106 uint112 reserve0,
File: /contracts/Oracles/UniswapV2PriceOracle.sol #14 107 uint112 reserve1,
File: /contracts/Oracles/UniswapV2PriceOracle.sol #15 108 uint32 blockTimestampLast
File: /contracts/Oracles/UniswapV2PriceOracle.sol #16 112 uint32 timeElapsed = uint32(block.timestamp % (2**32)) - blockTimestampLast;
private
rather than public
for constants, saves gasIf needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table
File: /contracts/Comptroller.sol #1 72 uint224 public constant compInitialIndex = 1e36;
File: /contracts/Oracles/CNftPriceOracle.sol #2 12 bool public constant isNftPriceOracle = true;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #3 17 uint256 public constant OBSERVATION_BUFFER_SIZE = 8;
File: /contracts/Oracles/UniswapV2PriceOracle.sol #4 18 uint256 public constant MIN_TWAP_TIME = 30 minutes;
if (<x> == true)
=> if (<x>)
, if (<x> == false)
=> if (!<x>)
File: /contracts/Comptroller.sol #1 142 if (marketToJoin.accountMembership[borrower] == true) {
File: /contracts/Comptroller.sol #2 997 require(msg.sender == admin || state == true, "only admin can unpause");
File: /contracts/Comptroller.sol #3 1011 require(msg.sender == admin || state == true, "only admin can unpause");
File: /contracts/Comptroller.sol #4 1020 require(msg.sender == admin || state == true, "only admin can unpause");
File: /contracts/Comptroller.sol #5 1029 require(msg.sender == admin || state == true, "only admin can unpause");
File: /contracts/Comptroller.sol #6 1065 require(market.isListed == true, "comp market is not listed");
File: /contracts/Comptroller.sol #7 1226 if (borrowers == true) {
File: /contracts/Comptroller.sol #8 1233 if (suppliers == true) {
File: /contracts/Comptroller.sol #9 1325 borrowGuardianPaused[address(cToken)] == true &&
require()
/revert()
checks should be refactored to a modifier or functionSaves deployment costs
File: /contracts/CNft.sol #1 116 require(tokenIds.length == amounts.length, "CNFT: id/amounts length mismatch");
File: /contracts/CNft.sol #2 124 require(amounts[i] == 1, "CNFT: Amounts must be all 1s for non-ERC1155s.");
File: /contracts/Comptroller.sol #3 1010 require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can pause");
File: /contracts/Comptroller.sol #4 1011 require(msg.sender == admin || state == true, "only admin can unpause");
File: /contracts/Comptroller.sol #5 1293 require(adminOrInitializing(), "only admin can set comp speed");
File: /contracts/CToken.sol #6 260 require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
File: /contracts/CToken.sol #7 1083 require(amountSeizeError == uint(Error.NO_ERROR), "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #8 149 require(length > 0, "UniswapV2PriceOracle: No observations.");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #9 152 require(length > 1, "UniswapV2PriceOracle: Only one observation.");
File: /contracts/Oracles/UniswapV2PriceOracle.sol #10 156 require( 157 block.timestamp - lastObservation.timestamp >= MIN_TWAP_TIME, 158 "UniswapV2PriceOracle: Bad TWAP time." 159 );
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/CEther.sol #1 188 require(errCode == uint(Error.NO_ERROR), string(fullMessage));
File: /contracts/CNft.sol #2 93 require(borrower != liquidator, "CNFT: Liquidator cannot be borrower");
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. The extra opcodes avoided are
CALLVALUE
(2),DUP1
(3),ISZERO
(3),PUSH2
(3),JUMPI
(10),PUSH1
(3),DUP1
(3),REVERT
(0),JUMPDEST
(1),POP
(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost
File: /contracts/CNft.sol #1 274 function call( 275 address to, 276 uint256 value, 277 bytes calldata data 278 ) external payable nonReentrant onlyOwner returns (bool success) {
File: /contracts/ERC1155Enumerable.sol #2 26 function __ERC1155Enumerable_init(string memory uri_) public onlyInitializing {
File: /contracts/Oracles/CNftPriceOracle.sol #3 54 function changeAdmin(address newAdmin) external onlyAdmin {
File: /contracts/Oracles/CNftPriceOracle.sol #4 58 function addAddressMapping( 59 CNftInterface[] calldata cNfts, 60 address[] calldata nftxTokens 61 ) external onlyAdmin {