Issue | Instances | |
---|---|---|
GAS-1 | Use assembly to check for address(0) |
9 |
GAS-2 | array[index] += amount is cheaper than array[index] = array[index] + amount (or related variants) |
8 |
GAS-3 | Using bools for storage incurs overhead | 7 |
GAS-4 | Cache array length outside of loop | 4 |
GAS-5 | State variables should be cached in stack variables rather than re-reading them from storage | 20 |
GAS-6 | Use calldata instead of memory for function arguments that do not get mutated | 19 |
GAS-7 | Use Custom Errors | 49 |
GAS-8 | Don't initialize variables with default value | 14 |
GAS-9 | Long revert strings | 11 |
GAS-10 | Functions guaranteed to revert when called by normal users can be marked payable |
7 |
GAS-11 | ++i costs less gas than i++ , especially when it's used in for -loops (--i /i-- too) |
2 |
GAS-12 | Using private rather than public for constants, saves gas |
27 |
GAS-13 | Use != 0 instead of > 0 for unsigned integer comparison | 6 |
GAS-14 | internal functions not called by the contract should be removed |
20 |
Saves 6 gas per instance
Instances (9):
File: contracts/cash/CashManager.sol
161: _grantRole(PAUSER_ADMIN, pauser);
165: feeRecipient = _feeRecipient;
167: assetSender = _assetSender;
170: mintLimit = _mintLimit;
174: currentEpochStartTimestamp =
File: contracts/cash/kyc/KYCRegistryClient.sol
57: emit KYCRequirementGroupSet(oldKYCLevel, _kycRequirementGroup);
File: contracts/cash/token/CashKYCSender.sol
77:
File: contracts/cash/token/CashKYCSenderReceiver.sol
85:
85:
[GAS-2] array[index] += amount
is cheaper than array[index] = array[index] + amount
(or related variants)
When updating a value in an array with arithmetic, using array[index] += amount
is cheaper than array[index] = array[index] + amount
.
This is because you avoid an additonal mload
when the array is stored in memory, and an sload
when the array is stored in storage.
This can be applied for any arithmetic operation including +=
, -=
,/=
,*=
,^=
,&=
, %=
, <<=
,>>=
, and >>>=
.
This optimization can be particularly significant if the pattern occurs during a loop.
Saves 28 gas for a storage array, 38 for a memory array
Instances (8):
File: contracts/lending/tokens/cCash/CTokenCash.sol
536: accountTokens[minter] = accountTokens[minter] + mintTokens;
642: accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens;
1041: accountTokens[borrower] = accountTokens[borrower] - seizeTokens;
1042: accountTokens[liquidator] =
File: contracts/lending/tokens/cToken/CTokenModified.sol
536: accountTokens[minter] = accountTokens[minter] + mintTokens;
642: accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens;
1044: accountTokens[borrower] = accountTokens[borrower] - seizeTokens;
1045: accountTokens[liquidator] =
Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See source.
Instances (7):
File: contracts/cash/kyc/KYCRegistry.sol
39: mapping(uint256 => mapping(address => bool)) public kycState;
File: contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol
17: bool internal _notEntered;
184: bool public constant isCToken = true;
File: contracts/lending/tokens/cErc20ModifiedDelegator.sol
187: bool internal _notEntered;
368: bool public constant isCToken = true;
File: contracts/lending/tokens/cToken/CTokenInterfacesModified.sol
15: bool internal _notEntered;
182: bool public constant isCToken = true;
If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).
Instances (4):
File: contracts/cash/CashManager.sol
961: for (uint256 i = 0; i < exCallData.length; ++i) {
File: contracts/cash/factory/CashFactory.sol
127: for (uint256 i = 0; i < exCallData.length; ++i) {
File: contracts/cash/factory/CashKYCSenderFactory.sol
137: for (uint256 i = 0; i < exCallData.length; ++i) {
File: contracts/cash/factory/CashKYCSenderReceiverFactory.sol
137: for (uint256 i = 0; i < exCallData.length; ++i) {
[GAS-5] State variables should be cached in stack variables rather than re-reading them from storage
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replaces each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
Saves 100 gas per instance
Instances (20):
File: contracts/cash/CashManager.sol
181: (IERC20Metadata(_cash).decimals() -
183: }
317: emit MintExchangeRateSet(epochToSet, oldExchangeRate, exchangeRate);
738: * minus those burned by users who are issued a
842: * amount of CASH a user has burned to kick off redemption process
File: contracts/cash/factory/CashFactory.sol
115: * @dev All external calls made through this function will
117: *
119: * 1) target - contract to call
125: ) external payable override onlyGuardian returns (bytes[] memory results) {
125: ) external payable override onlyGuardian returns (bytes[] memory results) {
File: contracts/cash/factory/CashKYCSenderFactory.sol
117: address(cashKYCSenderProxyAdmin),
124: *
126: * msg.sender == contract address
133: function multiexcall(
134: ExCallData[] calldata exCallData
File: contracts/cash/factory/CashKYCSenderReceiverFactory.sol
116: address(cashKYCSenderReceiverProxied),
118: address(cashKYCSenderReceiverImplementation)
123: * @notice Allows for arbitrary batched calls
131: * 3) value - eth value to call target with
133: function multiexcall(
Mark data types as calldata
instead of memory
where possible. This makes it so that the data is not automatically loaded into memory. If the data passed into the function does not need to be changed (like updating values in an array), it can be passed in as calldata
. The one exception to this is if the argument must later be passed into another function that takes an argument that specifies memory
storage.
Instances (19):
File: contracts/cash/Proxy.sol
27:
File: contracts/cash/token/CashKYCSender.sol
70: require(
71: _getKYCStatus(from),
File: contracts/cash/token/CashKYCSenderReceiver.sol
70: require(
71: _getKYCStatus(from),
File: contracts/lending/tokens/cCash/CCash.sol
35: string memory name_,
36: string memory symbol_,
File: contracts/lending/tokens/cCash/CCashDelegate.sol
21: function _becomeImplementation(bytes memory data) public virtual override {
File: contracts/lending/tokens/cCash/CTokenCash.sol
38: string memory name_,
39: string memory symbol_,
File: contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol
443: bytes memory becomeImplementationData
453: function _becomeImplementation(bytes memory data) external virtual;
File: contracts/lending/tokens/cToken/CErc20.sol
35: string memory name_,
36: string memory symbol_,
File: contracts/lending/tokens/cToken/CTokenDelegate.sol
21: function _becomeImplementation(bytes memory data) public virtual override {
File: contracts/lending/tokens/cToken/CTokenInterfacesModified.sol
441: bytes memory becomeImplementationData
451: function _becomeImplementation(bytes memory data) external virtual;
File: contracts/lending/tokens/cToken/CTokenModified.sol
38: string memory name_,
39: string memory symbol_,
Source Instead of using error strings, to reduce deployment and runtime cost, you should use Custom Errors. This would save both deployment and runtime cost.
Instances (49):
File: contracts/cash/CashManager.sol
965: require(success, "Call Failed");
File: contracts/cash/factory/CashFactory.sol
131: require(success, "Call Failed");
152: require(msg.sender == guardian, "CashFactory: You are not the Guardian");
File: contracts/cash/factory/CashKYCSenderFactory.sol
141: require(success, "Call Failed");
File: contracts/cash/factory/CashKYCSenderReceiverFactory.sol
141: require(success, "Call Failed");
File: contracts/cash/kyc/KYCRegistry.sol
87: require(v == 27 || v == 28, "KYCRegistry: invalid v value in signature");
92: require(block.timestamp <= deadline, "KYCRegistry: signature expired");
File: contracts/lending/JumpRateModelV2.sol
89: require(msg.sender == owner, "only the owner may call this function.");
File: contracts/lending/OndoPriceOracleV2.sol
110: revert("Oracle type not supported");
297: require(answer >= 0, "Price cannot be negative");
File: contracts/lending/tokens/cCash/CCash.sol
220: require(success, "TOKEN_TRANSFER_IN_FAILED");
260: require(success, "TOKEN_TRANSFER_OUT_FAILED");
File: contracts/lending/tokens/cCash/CTokenCash.sol
44: require(msg.sender == admin, "only admin may initialize the market");
59: require(err == NO_ERROR, "setting comptroller failed");
67: require(err == NO_ERROR, "setting interest rate model failed");
97: require(_getKYCStatus(spender), "Spender not KYC'd");
98: require(_getKYCStatus(src), "Source not KYC'd");
99: require(_getKYCStatus(dst), "Destination not KYC'd");
493: require(_getKYCStatus(minter), "Minter not KYC'd");
582: require(_getKYCStatus(redeemer), "Redeemer not KYC'd");
681: require(_getKYCStatus(borrower), "Borrower not KYC'd");
773: require(_getKYCStatus(payer), "Payer not KYC'd");
774: require(_getKYCStatus(borrower), "Borrower not KYC'd");
997: require(_getKYCStatus(liquidator), "Liquidator not KYC'd");
998: require(_getKYCStatus(borrower), "Borrower not KYC'd");
1122: require(newComptroller.isComptroller(), "marker method returned false");
1357: require(msg.sender == admin, "Only admin can set KYC requirement group");
1379: require(msg.sender == admin, "Only admin can set KYC registry");
1389: require(_kycRegistry != address(0), "KYC registry cannot be zero address");
1435: require(_notEntered, "re-entered");
File: contracts/lending/tokens/cToken/CErc20.sol
220: require(success, "TOKEN_TRANSFER_IN_FAILED");
260: require(success, "TOKEN_TRANSFER_OUT_FAILED");
File: contracts/lending/tokens/cToken/CTokenModified.sol
44: require(msg.sender == admin, "only admin may initialize the market");
59: require(err == NO_ERROR, "setting comptroller failed");
67: require(err == NO_ERROR, "setting interest rate model failed");
97: require(!sanctionsList.isSanctioned(spender), "Spender is sanctioned");
98: require(!sanctionsList.isSanctioned(src), "Source is sanctioned");
99: require(!sanctionsList.isSanctioned(dst), "Destination is sanctioned");
493: require(!sanctionsList.isSanctioned(minter), "Minter is sanctioned");
582: require(!sanctionsList.isSanctioned(redeemer), "Redeemer is sanctioned");
681: require(_getKYCStatus(borrower), "Borrower not KYC'd");
773: require(_getKYCStatus(payer), "Payer not KYC'd");
774: require(_getKYCStatus(borrower), "Borrower not KYC'd");
1001: require(!sanctionsList.isSanctioned(borrower), "Borrower is sanctioned");
1125: require(newComptroller.isComptroller(), "marker method returned false");
1360: require(msg.sender == admin, "Only admin can set KYC requirement group");
1382: require(msg.sender == admin, "Only admin can set KYC registry");
1392: require(_kycRegistry != address(0), "KYC registry cannot be zero address");
1438: require(_notEntered, "re-entered");
Instances (14):
File: contracts/cash/CashManager.sol
64: uint256 public mintFee = 0;
581: currentMintAmount = 0;
750: for (uint256 i = 0; i < size; ++i) {
786: for (uint256 i = 0; i < size; ++i) {
933: for (uint256 i = 0; i < size; ++i) {
961: for (uint256 i = 0; i < exCallData.length; ++i) {
File: contracts/cash/factory/CashFactory.sol
127: for (uint256 i = 0; i < exCallData.length; ++i) {
File: contracts/cash/factory/CashKYCSenderFactory.sol
137: for (uint256 i = 0; i < exCallData.length; ++i) {
File: contracts/cash/factory/CashKYCSenderReceiverFactory.sol
137: for (uint256 i = 0; i < exCallData.length; ++i) {
File: contracts/cash/kyc/KYCRegistry.sol
163: for (uint256 i = 0; i < length; i++) {
180: for (uint256 i = 0; i < length; i++) {
File: contracts/lending/tokens/cCash/CTokenCash.sol
113: uint startingAllowance = 0;
File: contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol
115: uint public constant protocolSeizeShareMantissa = 0; //0%
File: contracts/lending/tokens/cToken/CTokenModified.sol
113: uint startingAllowance = 0;
Instances (11):
File: contracts/cash/factory/CashFactory.sol
152: require(msg.sender == guardian, "CashFactory: You are not the Guardian");
File: contracts/cash/kyc/KYCRegistry.sol
87: require(v == 27 || v == 28, "KYCRegistry: invalid v value in signature");
File: contracts/lending/JumpRateModelV2.sol
89: require(msg.sender == owner, "only the owner may call this function.");
File: contracts/lending/tokens/cCash/CTokenCash.sol
44: require(msg.sender == admin, "only admin may initialize the market");
67: require(err == NO_ERROR, "setting interest rate model failed");
1357: require(msg.sender == admin, "Only admin can set KYC requirement group");
1389: require(_kycRegistry != address(0), "KYC registry cannot be zero address");
File: contracts/lending/tokens/cToken/CTokenModified.sol
44: require(msg.sender == admin, "only admin may initialize the market");
67: require(err == NO_ERROR, "setting interest rate model failed");
1360: require(msg.sender == admin, "Only admin can set KYC requirement group");
1392: require(_kycRegistry != address(0), "KYC registry cannot be zero address");
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.
Instances (7):
File: contracts/cash/CashManager.sol
526: function pause() external onlyRole(PAUSER_ADMIN) {
533: function unpause() external onlyRole(MANAGER_ADMIN) {
596: function setMintLimit(uint256 _mintLimit) external onlyRole(MANAGER_ADMIN) {
File: contracts/lending/OndoPriceOracle.sol
80: function setPrice(address fToken, uint256 price) external override onlyOwner {
106: function setOracle(address newOracle) external override onlyOwner {
File: contracts/lending/OndoPriceOracleV2.sol
163: function setPrice(address fToken, uint256 price) external override onlyOwner {
182: function setOracle(address newOracle) external override onlyOwner {
Saves 5 gas per loop
Instances (2):
File: contracts/cash/kyc/KYCRegistry.sol
163: for (uint256 i = 0; i < length; i++) {
180: for (uint256 i = 0; i < length; i++) {
If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table
Instances (27):
File: contracts/cash/CashManager.sol
89: uint256 public constant BPS_DENOMINATOR = 10_000;
122: bytes32 public constant MANAGER_ADMIN = keccak256("MANAGER_ADMIN");
123: bytes32 public constant PAUSER_ADMIN = keccak256("PAUSER_ADMIN");
124: bytes32 public constant SETTER_ADMIN = keccak256("SETTER_ADMIN");
File: contracts/cash/factory/CashFactory.sol
44: bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
45: bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
46: bytes32 public constant DEFAULT_ADMIN_ROLE = bytes32(0);
File: contracts/cash/factory/CashKYCSenderFactory.sol
44: bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
45: bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
46: bytes32 public constant DEFAULT_ADMIN_ROLE = bytes32(0);
File: contracts/cash/factory/CashKYCSenderReceiverFactory.sol
44: bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
45: bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
46: bytes32 public constant DEFAULT_ADMIN_ROLE = bytes32(0);
File: contracts/cash/kyc/KYCRegistry.sol
31: bytes32 public constant _APPROVAL_TYPEHASH =
36: bytes32 public constant REGISTRY_ADMIN = keccak256("REGISTRY_ADMIN");
File: contracts/cash/token/Cash.sol
22: bytes32 public constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
File: contracts/cash/token/CashKYCSender.sol
26: bytes32 public constant KYC_CONFIGURER_ROLE =
File: contracts/cash/token/CashKYCSenderReceiver.sol
26: bytes32 public constant KYC_CONFIGURER_ROLE =
File: contracts/lending/JumpRateModelV2.sol
29: uint public constant blocksPerYear = 2628000;
File: contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol
115: uint public constant protocolSeizeShareMantissa = 0; //0%
166: ISanctionsList public constant sanctionsList =
184: bool public constant isCToken = true;
File: contracts/lending/tokens/cErc20ModifiedDelegator.sol
350: ISanctionsList public constant sanctionsList =
368: bool public constant isCToken = true;
File: contracts/lending/tokens/cToken/CTokenInterfacesModified.sol
113: uint public constant protocolSeizeShareMantissa = 1.75e16; //1.75%
164: ISanctionsList public constant sanctionsList =
182: bool public constant isCToken = true;
Instances (6):
File: contracts/cash/CashManager.sol
579: if (epochDifference > 0) {
File: contracts/lending/OndoPriceOracleV2.sol
114: if (fTokenToUnderlyingPriceCap[fToken] > 0) {
File: contracts/lending/tokens/cCash/CTokenCash.sol
53: initialExchangeRateMantissa > 0,
595: if (redeemTokensIn > 0) {
File: contracts/lending/tokens/cToken/CTokenModified.sol
53: initialExchangeRateMantissa > 0,
595: if (redeemTokensIn > 0) {
If the functions are required by an interface, the contract should inherit from that interface and use the override
keyword
Instances (20):
File: contracts/lending/tokens/cCash/CTokenCash.sol
479: function mintInternal(uint mintAmount) internal nonReentrant {
552: function redeemInternal(uint redeemTokens) internal nonReentrant {
563: function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant {
669: function borrowInternal(uint borrowAmount) internal nonReentrant {
740: function repayBorrowInternal(uint repayAmount) internal nonReentrant {
751: function repayBorrowBehalfInternal(
845: function liquidateBorrowInternal(
1182: function _addReservesInternal(
File: contracts/lending/tokens/cToken/CTokenModified.sol
479: function mintInternal(uint mintAmount) internal nonReentrant {
552: function redeemInternal(uint redeemTokens) internal nonReentrant {
563: function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant {
669: function borrowInternal(uint borrowAmount) internal nonReentrant {
740: function repayBorrowInternal(uint repayAmount) internal nonReentrant {
751: function repayBorrowBehalfInternal(
845: function liquidateBorrowInternal(
1185: function _addReservesInternal(
Issue | Instances | |
---|---|---|
NC-1 | Missing checks for address(0) when assigning values to address state variables |
6 |
NC-2 | Return values of approve() not checked |
1 |
NC-3 | Event is missing indexed fields |
74 |
NC-4 | Constants should be defined rather than using magic numbers | 1 |
NC-5 | Functions not used internally could be marked external | 8 |
Instances (6):
File: contracts/cash/CashManager.sol
477: * @param collateralAmountIn Amount of `collateral` to exchange
485: * bringing us down to 18 decimals of precision
826: * @notice Custom view function to return the quantity burned by
File: contracts/cash/factory/CashFactory.sol
70: * address specified in constructor.
File: contracts/cash/factory/CashKYCSenderFactory.sol
70: * address specified in constructor.
File: contracts/cash/factory/CashKYCSenderReceiverFactory.sol
70: * address specified in constructor.
Not all IERC20 implementations revert()
when there's a failure in approve()
. The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually approving anything
Instances (1):
File: contracts/lending/tokens/cErc20ModifiedDelegator.sol
902: abi.encodeWithSignature("approve(address,uint256)", spender, amount)
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
Instances (74):
File: contracts/cash/factory/CashFactory.sol
156:
File: contracts/cash/factory/CashKYCSenderFactory.sol
170:
File: contracts/cash/factory/CashKYCSenderReceiverFactory.sol
170:
File: contracts/cash/interfaces/ICashManager.sol
95: * @notice Event emitted when minimum deposit amount is set
102: event MinimumDepositAmountSet(uint256 oldMinimum, uint256 newMinimum);
111: event MinimumRedeemAmountSet(uint256 oldRedeemMin, uint256 newRedeemMin);
124: * @notice Event emitted when exchange rate is set for
133: event MintExchangeRateSet(
143: * @param epoch Epoch in which the mint exchange rate was
151: event MintExchangeRateOverridden(
173: * @dev Both rates are represented in 6 decimals.
186: *
199: event RedeemLimitSet(uint256 oldLimit, uint256 newLimit);
212: * @notice Event emitted when redemption request is submitted
218: event RedemptionRequested(
228: * @param collateralAmountDeposited The total amount deposited
237: uint256 depositAmountAfterFee,
248: * requested
265: * @param epochClaimedFrom The epoch in which the user requested
286: uint256 collateralAmountOut,
306: * @param user The address of the user having their mint balance set
319: * @notice Event emitted when a user redemption balance is set manually
330: uint256 balance,
352: error MintFeeTooLarge();
File: contracts/cash/interfaces/IKYCRegistryClient.sol
61:
61:
File: contracts/cash/kyc/KYCRegistry.sol
224: address indexed sender,
244:
File: contracts/lending/IOndoPriceOracle.sol
66: event CTokenOracleSet(address oldOracle, address newOracle);
68:
68:
File: contracts/lending/IOndoPriceOracleV2.sol
66: event CTokenOracleSet(address oldOracle, address newOracle);
80: function setFTokenToChainlinkOracle(
92: ) external;
126: event MaxChainlinkOracleTimeDelaySet(
137: event FTokenToOracleTypeSet(address indexed fToken, OracleType oracleType);
139:
139:
File: contracts/lending/tokens/cCash/CTokenInterfacesModifiedCash.sol
150: event KYCRegistrySet(address oldRegistry, address newRegistry);
158: event KYCRequirementGroupSet(
191: event AccrueInterest(
201: event Mint(address minter, uint mintAmount, uint mintTokens);
206: event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);
211: event Borrow(
221: event RepayBorrow(
232: event LiquidateBorrow(
245: event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
250: event NewAdmin(address oldAdmin, address newAdmin);
255: event NewComptroller(
263: event NewMarketInterestRateModel(
271: event NewReserveFactor(
279: event ReservesAdded(
288: event ReservesReduced(
297: event Transfer(address indexed from, address indexed to, uint amount);
302: event Approval(address indexed owner, address indexed spender, uint amount);
432: event NewImplementation(address oldImplementation, address newImplementation);
File: contracts/lending/tokens/cToken/CTokenInterfacesModified.sol
148: event KYCRegistrySet(address oldRegistry, address newRegistry);
156: event KYCRequirementGroupSet(
189: event AccrueInterest(
199: event Mint(address minter, uint mintAmount, uint mintTokens);
204: event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);
209: event Borrow(
219: event RepayBorrow(
230: event LiquidateBorrow(
243: event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
248: event NewAdmin(address oldAdmin, address newAdmin);
253: event NewComptroller(
261: event NewMarketInterestRateModel(
269: event NewReserveFactor(
277: event ReservesAdded(
286: event ReservesReduced(
295: event Transfer(address indexed from, address indexed to, uint amount);
300: event Approval(address indexed owner, address indexed spender, uint amount);
430: event NewImplementation(address oldImplementation, address newImplementation);
Instances (1):
File: contracts/lending/OndoPriceOracleV2.sol
261: (36 -
Instances (8):
File: contracts/cash/token/CashKYCSender.sol
69: // Only check KYC if not minting
File: contracts/cash/token/CashKYCSenderReceiver.sol
69: // Only check KYC if not minting
File: contracts/lending/tokens/cCash/CCash.sol
30: function initialize(
File: contracts/lending/tokens/cCash/CTokenCash.sol
34: function initialize(
1300: function _setInterestRateModel(
File: contracts/lending/tokens/cToken/CErc20.sol
30: function initialize(
File: contracts/lending/tokens/cToken/CTokenModified.sol
34: function initialize(
1303: function _setInterestRateModel(
Issue | Instances | |
---|---|---|
L-1 | Unsafe ERC20 operation(s) | 6 |
Instances (6):
File: contracts/lending/tokens/cCash/CCash.sol
160: token.transfer(admin, balance);
201: token.transferFrom(from, address(this), amount);
241: token.transfer(to, amount);
File: contracts/lending/tokens/cToken/CErc20.sol
160: token.transfer(admin, balance);
201: token.transferFrom(from, address(this), amount);
241: token.transfer(to, amount);
Issue | Instances | |
---|---|---|
M-1 | Centralization Risk for trusted owners | 41 |
Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.
Instances (41):
File: contracts/cash/CashManager.sol
31: AccessControlEnumerable,
284: ) external override updateEpoch onlyRole(SETTER_ADMIN) {
341: ) external updateEpoch onlyRole(MANAGER_ADMIN) {
370: ) external override updateEpoch onlyRole(MANAGER_ADMIN) {
394: ) external override onlyRole(MANAGER_ADMIN) {
412: ) external override onlyRole(MANAGER_ADMIN) {
435: ) external override onlyRole(MANAGER_ADMIN) {
454: ) external override onlyRole(MANAGER_ADMIN) {
467: ) external override onlyRole(MANAGER_ADMIN) {
526: function pause() external onlyRole(PAUSER_ADMIN) {
533: function unpause() external onlyRole(MANAGER_ADMIN) {
548: ) external onlyRole(MANAGER_ADMIN) {
596: function setMintLimit(uint256 _mintLimit) external onlyRole(MANAGER_ADMIN) {
611: ) external onlyRole(MANAGER_ADMIN) {
713: ) external override updateEpoch onlyRole(MANAGER_ADMIN) {
805: ) external onlyRole(MANAGER_ADMIN) {
819: ) external onlyRole(MANAGER_ADMIN) {
855: ) external updateEpoch onlyRole(MANAGER_ADMIN) {
898: ) external override onlyRole(MANAGER_ADMIN) {
909: ) external override onlyRole(MANAGER_ADMIN) {
956: onlyRole(MANAGER_ADMIN)
File: contracts/cash/kyc/KYCRegistry.sol
30: contract KYCRegistry is AccessControlEnumerable, IKYCRegistry, EIP712 {
147: ) external onlyRole(REGISTRY_ADMIN) {
161: ) external onlyRole(kycGroupRoles[kycRequirementGroup]) {
178: ) external onlyRole(kycGroupRoles[kycRequirementGroup]) {
File: contracts/cash/token/CashKYCSender.sol
36: ) external override onlyRole(KYC_CONFIGURER_ROLE) {
42: ) external override onlyRole(KYC_CONFIGURER_ROLE) {
File: contracts/cash/token/CashKYCSenderReceiver.sol
36: ) external override onlyRole(KYC_CONFIGURER_ROLE) {
42: ) external override onlyRole(KYC_CONFIGURER_ROLE) {
File: contracts/lending/OndoPriceOracle.sol
39: contract OndoPriceOracle is IOndoPriceOracle, Ownable {
80: function setPrice(address fToken, uint256 price) external override onlyOwner {
95: ) external override onlyOwner {
106: function setOracle(address newOracle) external override onlyOwner {
File: contracts/lending/OndoPriceOracleV2.sol
49: contract OndoPriceOracleV2 is IOndoPriceOracleV2, Ownable {
133: ) external override onlyOwner {
148: ) external override onlyOwner {
163: function setPrice(address fToken, uint256 price) external override onlyOwner {
182: function setOracle(address newOracle) external override onlyOwner {
197: ) external override onlyOwner {
236: ) external override onlyOwner {
311: ) external override onlyOwner {