Issue | Instances | |
---|---|---|
GAS-1 | Using bools for storage incurs overhead | 5 |
GAS-2 | Cache array length outside of loop | 2 |
GAS-3 | Use Custom Errors | 138 |
GAS-4 | Don't initialize variables with default value | 2 |
GAS-5 | Long revert strings | 10 |
GAS-6 | Functions guaranteed to revert when called by normal users can be marked payable |
10 |
GAS-7 | Splitting require() statements that use && saves gas | 7 |
GAS-8 | Use != 0 instead of > 0 for unsigned integer comparison | 20 |
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 (5):
File: contracts/Repository.sol
24: mapping(bytes32 => bool) public validRoles;
File: contracts/StabilityPod/StabilizerNode.sol
69: bool internal trackAfterStabilize = true;
70: bool public onlyStabilizeToPeg = false;
71: bool public usePrimedWindow;
File: contracts/Token/Malt.sol
21: bool internal initialSetup;
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 (2):
File: contracts/Token/Malt.sol
110: for (uint256 i = 0; i < minters.length; i = i + 1) {
114: for (uint256 i = 0; i < burners.length; i = i + 1) {
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 (138):
File: contracts/DataFeed/MaltDataLab.sol
78: require(!contractActive, "MaltDataLab: Already setup");
79: require(_malt != address(0), "MaltDataLab: Malt addr(0)");
80: require(_collateralToken != address(0), "MaltDataLab: Col addr(0)");
81: require(_stakeToken != address(0), "MaltDataLab: LP Token addr(0)");
82: require(_poolMA != address(0), "MaltDataLab: PoolMA addr(0)");
91: require(_globalIC != address(0), "MaltDataLab: GlobalIC addr(0)");
92: require(_ratioMA != address(0), "MaltDataLab: RatioMA addr(0)");
523: require(_price > 0, "Cannot have 0 price");
537: require(_lookback > 0, "Cannot have 0 lookback");
545: require(_lookback > 0, "Cannot have 0 lookback");
553: require(_lookback > 0, "Cannot have 0 lookback");
561: require(_lookback > 0, "Cannot have 0 lookback");
569: require(_poolMA != address(0), "Cannot use 0 address");
577: require(_ratioMA != address(0), "Cannot use 0 address");
585: require(_z != 0, "Cannot have 0 for Z");
586: require(_z <= 100, "Cannot be over 100");
594: require(_swingTraderLowBps != 0, "Cannot have 0 Swing Trader Low BPS");
606: require(_breakpointBps != 0, "Cannot have 0 breakpoint BPS");
File: contracts/GlobalImpliedCollateralService.sol
55: require(_repository != address(0), "GlobImpCol: Timelock addr(0)");
56: require(initialAdmin != address(0), "GlobImpCol: Admin addr(0)");
57: require(_malt != address(0), "GlobImpCol: Malt addr(0)");
112: require(_updater != address(0), "GlobImpCol: No addr(0)");
223: require(msg.sender == deployer, "Only deployer");
224: require(_updaterManager != address(0), "Cannot use addr(0)");
225: require(updaterManager == address(0), "Initial updater already set");
237: require(_updaterManager != address(0), "Cannot use addr(0)");
245: require(msg.sender == proposedManager, "Must be proposedManager");
File: contracts/Repository.sol
54: require(msg.sender == deployer, "Must be deployer");
91: require(validRoles[role], "Unknown role");
129: require(validRoles[role], "Unknown role");
134: require(account != address(0), "0x0");
143: require(destination != address(0), "Withdraw: addr(0)");
146: require(success, "emergencyWithdrawGAS error");
153: require(destination != address(0), "Withdraw: addr(0)");
163: require(destination != address(0), "Withdraw: addr(0)");
165: require(success, "partialWithdrawGAS error");
173: require(destination != address(0), "Withdraw: addr(0)");
190: require(account != address(0), "0x0");
213: require(_contract != address(0), "0x0");
216: require(currentContract.contractAddress == address(0), "Contract exists");
237: require(_newContract != address(0), "0x0");
File: contracts/RewardSystem/LinearDistributor.sol
61: require(!contractActive, "Distributor: Setup already done");
62: require(_collateralToken != address(0), "Distributor: Col addr(0)");
63: require(_rewardMine != address(0), "Distributor: RewardMine addr(0)");
64: require(_rewardThrottle != address(0), "Distributor: Throttler addr(0)");
65: require(_forfeitor != address(0), "Distributor: Forfeitor addr(0)");
175: require(reward > 0, "Cannot declare 0 reward");
182: require(declaredBalance <= totalReward, "Insufficient balance");
186: require(forfeited <= declaredBalance, "Cannot forfeit more than declared");
196: require(declaredBalance <= totalReward, "Insufficient balance");
209: require(_rewardMine != address(0), "Cannot set 0 address as rewardMine");
218: require(_forfeitor != address(0), "Cannot set 0 address as forfeitor");
226: require(_vestingDistributor != address(0), "SetVestDist: No addr(0)");
File: contracts/RewardSystem/RewardThrottle.sol
67: require(_timekeeper != address(0), "Throttle: Timekeeper addr(0)");
79: require(!contractActive, "RewardThrottle: Already setup");
80: require(_collateralToken != address(0), "RewardThrottle: Col addr(0)");
81: require(_overflowPool != address(0), "RewardThrottle: Overflow addr(0)");
82: require(_bonding != address(0), "RewardThrottle: Bonding addr(0)");
250: require(startEpoch <= endEpoch, "Start cannot be before the end");
320: require(startEpoch <= endEpoch, "Start cannot be before the end");
466: require(epoch <= actualEpoch && epoch > activeEpoch, "Invalid epoch");
694: require(_timekeeper != address(0), "Not address 0");
702: require(_smoothingPeriod > 0, "No zero smoothing period");
710: require(_runway > 604800, "Runway must be > 1 week");
718: require(_aprCap != 0, "Cap cannot be 0");
726: require(_aprFloor != 0, "Floor cannot be 0");
734: require(_period >= timekeeper.epochLength(), "< 1 epoch");
742: require(_cushionBps != 0, "Cannot be 0");
750: require(_max != 0, "Cannot be 0");
758: require(_gain != 0 && _gain < 10000, "Between 1-9999 inc");
File: contracts/StabilityPod/ImpliedCollateralService.sol
60: require(!contractActive, "ImpCol: Already setup");
61: require(_auction != address(0), "ImpCol: Auction addr(0)");
62: require(_rewardOverflow != address(0), "ImpCol: Overflow addr(0)");
63: require(_swingTraderManager != address(0), "ImpCol: Swing addr(0)");
64: require(_liquidityExtension != address(0), "ImpCol: LE addr(0)");
65: require(_maltDataLab != address(0), "ImpCol: DataLab addr(0)");
66: require(_stabilizerNode != address(0), "ImpCol: StablizerNode addr(0)");
67: require(_globalIC != address(0), "ImpCol: GlobalIC addr(0)");
68: require(_collateralToken != address(0), "ImpCol: ColToken addr(0)");
69: require(_malt != address(0), "ImpCol: Malt addr(0)");
70: require(_stakeToken != address(0), "ImpCol: Stake Token addr(0)");
File: contracts/StabilityPod/StabilizerNode.sol
125: require(!contractActive, "StabilizerNode: Already setup");
126: require(_malt != address(0), "StabilizerNode: Malt addr(0)");
127: require(_collateralToken != address(0), "StabilizerNode: Col addr(0)");
128: require(_dexHandler != address(0), "StabilizerNode: DexHandler addr(0)");
129: require(_maltDataLab != address(0), "StabilizerNode: DataLab addr(0)");
138: require(_auction != address(0), "StabilizerNode: Auction addr(0)");
205: require(livePrice < upperBand, "Stabilize: Beyond upper bound");
206: require(livePrice > minThreshold, "Stabilize: Slippage threshold");
217: require(livePrice > lowerBand, "Stabilize: Beyond lower bound");
249: require(block.timestamp >= lastTracking + trackingBackoff, "Too early");
251: require(success, "Too early");
458: require(_period > 0, "Must be greater than 0");
467: require(_incentive != 0 && _incentive <= 1000, "Incentive out of range");
479: require(_incentive != 0 && _incentive <= 100000, "Incentive out of range");
493: require(amount > 0, "No negative damping");
503: require(_upper != 0 && _lower != 0, "Must be above 0");
504: require(_lower < 10000, "Lower to large");
533: require(_period > 0, "Cannot have 0 period");
554: require(_period > 0, "Cannot have 0 period");
563: require(_upper != 0 && _lower != 0, "Cannot have 0 band limit");
573: require(_slippageBps <= 10000, "slippage: Must be <= 100%");
598: require(_backoff != 0, "Cannot be 0");
623: require(_callerCut <= 1000, "Must be less than 10%");
643: require(_primedWindow != 0, "Cannot be 0");
File: contracts/StabilityPod/SwingTraderManager.sol
74: require(!contractActive, "SwingTraderManager: Already setup");
79: require(_malt != address(0), "SwingTraderManager: Malt addr(0)");
404: require(traderId > 2 && trader.id == 0, "TraderId already used");
405: require(_swingTrader != address(0), "addr(0)");
425: require(trader.id == traderId, "Unknown trader");
File: contracts/Token/Malt.sol
46: require(_repository != address(0), "Malt: Repo addr(0)");
47: require(_transferService != address(0), "Malt: XferSvc addr(0)");
99: require(msg.sender == deployer, "Only deployer");
100: require(!initialSetup, "Malt: Already setup");
101: require(_globalIC != address(0), "Malt: GlobalIC addr(0)");
102: require(_manager != address(0), "Malt: Manager addr(0)");
111: require(minters[i] != address(0), "Malt: Minter addr(0)");
115: require(burners[i] != address(0), "Malt: Burner addr(0)");
148: require(_burner != address(0), "No addr(0)");
157: require(_minter != address(0), "No addr(0)");
198: require(_manager != address(0), "Cannot use addr(0)");
206: require(msg.sender == proposedManager, "Must be proposedManager");
217: require(_service != address(0), "Cannot use address 0 as transfer service");
226: require(_service != address(0), "Cannot use address 0 as global ic");
File: contracts/Token/TransferService.sol
37: require(_repository != address(0), "XferSvc: Repo addr(0)");
38: require(initialAdmin != address(0), "XferSvc: Admin addr(0)");
67: require(success, "TransferService: External failure");
72: require(success, "TransferService: External failure");
152: require(_verifier != address(0), "Cannot use address 0");
153: require(_address != address(0), "Cannot use address 0");
155: require(verifiers[_address] == address(0), "Address already exists");
167: require(_address != address(0), "Cannot use address 0");
168: require(verifiers[_address] != address(0), "Address does not exists");
181: require(msg.sender == deployer, "Only deployer");
182: require(_verifierManager != address(0), "Cannot use addr(0)");
183: require(verifierManager == address(0), "Initial verifier already set");
195: require(_verifierManager != address(0), "Cannot use addr(0)");
203: require(msg.sender == proposedManager, "Must be proposedManager");
Instances (2):
File: contracts/Token/Malt.sol
110: for (uint256 i = 0; i < minters.length; i = i + 1) {
114: for (uint256 i = 0; i < burners.length; i = i + 1) {
Instances (10):
File: contracts/DataFeed/MaltDataLab.sol
594: require(_swingTraderLowBps != 0, "Cannot have 0 Swing Trader Low BPS");
File: contracts/RewardSystem/LinearDistributor.sol
186: require(forfeited <= declaredBalance, "Cannot forfeit more than declared");
209: require(_rewardMine != address(0), "Cannot set 0 address as rewardMine");
218: require(_forfeitor != address(0), "Cannot set 0 address as forfeitor");
File: contracts/StabilityPod/StabilizerNode.sol
128: require(_dexHandler != address(0), "StabilizerNode: DexHandler addr(0)");
File: contracts/StabilityPod/SwingTraderManager.sol
74: require(!contractActive, "SwingTraderManager: Already setup");
File: contracts/Token/Malt.sol
217: require(_service != address(0), "Cannot use address 0 as transfer service");
226: require(_service != address(0), "Cannot use address 0 as global ic");
File: contracts/Token/TransferService.sol
67: require(success, "TransferService: External failure");
72: require(success, "TransferService: External failure");
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 (10):
File: contracts/DataFeed/MaltDataLab.sol
297: function trackPool() external onlyActive returns (bool) {
File: contracts/Repository.sol
95: function addNewRole(bytes32 role) external onlyRole(TIMELOCK_ROLE) {
99: function removeRole(bytes32 role) external onlyRole(getRoleAdmin(role)) {
File: contracts/RewardSystem/RewardThrottle.sol
94: function handleReward() external onlyActive {
131: function updateDesiredAPR() public onlyActive {
437: function checkRewardUnderflow() public onlyActive {
File: contracts/StabilityPod/ImpliedCollateralService.sol
89: function syncGlobalCollateral() public onlyActive {
File: contracts/StabilityPod/StabilizerNode.sol
161: function stabilize() external nonReentrant onlyEOA onlyActive whenNotPaused {
239: function endAuctionEarly() external onlyActive whenNotPaused {
248: function trackPool() external onlyActive {
Instances (7):
File: contracts/RewardSystem/RewardThrottle.sol
466: require(epoch <= actualEpoch && epoch > activeEpoch, "Invalid epoch");
758: require(_gain != 0 && _gain < 10000, "Between 1-9999 inc");
File: contracts/StabilityPod/StabilizerNode.sol
467: require(_incentive != 0 && _incentive <= 1000, "Incentive out of range");
479: require(_incentive != 0 && _incentive <= 100000, "Incentive out of range");
503: require(_upper != 0 && _lower != 0, "Must be above 0");
563: require(_upper != 0 && _lower != 0, "Cannot have 0 band limit");
File: contracts/StabilityPod/SwingTraderManager.sol
404: require(traderId > 2 && trader.id == 0, "TraderId already used");
Instances (20):
File: contracts/DataFeed/MaltDataLab.sol
333: maltPriceCumulativeLast > 0 && priceCumulative == maltPriceCumulativeLast
523: require(_price > 0, "Cannot have 0 price");
537: require(_lookback > 0, "Cannot have 0 lookback");
545: require(_lookback > 0, "Cannot have 0 lookback");
553: require(_lookback > 0, "Cannot have 0 lookback");
561: require(_lookback > 0, "Cannot have 0 lookback");
File: contracts/RewardSystem/LinearDistributor.sol
130: if (distributed > 0) {
168: if (amount > 0) {
175: require(reward > 0, "Cannot declare 0 reward");
File: contracts/RewardSystem/RewardThrottle.sol
109: if (aprTarget > 0 && _epochAprGivenReward(epoch, balance) > aprTarget) {
113: if (remainder > 0) {
124: if (balance > 0) {
449: if (underflow > 0) {
629: if (_activeEpoch > 0) {
702: require(_smoothingPeriod > 0, "No zero smoothing period");
File: contracts/StabilityPod/StabilizerNode.sol
458: require(_period > 0, "Must be greater than 0");
493: require(amount > 0, "No negative damping");
533: require(_period > 0, "Cannot have 0 period");
554: require(_period > 0, "Cannot have 0 period");
File: contracts/StabilityPod/SwingTraderManager.sol
315: if (netBalance > 0) {
Issue | Instances | |
---|---|---|
NC-1 | TODO Left in the code | 3 |
TODOs may signal that a feature is missing or not ready for audit, consider resolving the issue and removing the TODO comment
Instances (3):
File: contracts/DataFeed/MaltDataLab.sol
212: // TODO MaltDataLab.sol will this work with other decimals? Sat 22 Oct 2022 18:44:07 BST
File: contracts/StabilityPod/StabilizerNode.sol
352: // TODO StabilizerNode.sol these checks won't work when working with pools not pegged to 1 Wed 26 Oct 2022 16:40:25 BST
441: // TODO StabilizerNode.sol invert priceTarget? Fri 21 Oct 2022 11:02:43 BST
Issue | Instances | |
---|---|---|
L-1 | abi.encodePacked() should not be used with dynamic types when passing the result to a hash function such as keccak256() |
5 |
L-2 | Do not use deprecated library functions | 3 |
L-3 | Empty Function Body - Consider commenting why | 1 |
[L-1] 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.
If all arguments are strings and or bytes, bytes.concat()
should be used instead
Instances (5):
File: contracts/Repository.sol
77: bytes32 hashedRole = keccak256(abi.encodePacked(_role));
82: bytes32 hashedContract = keccak256(abi.encodePacked(_contract));
214: bytes32 hashedName = keccak256(abi.encodePacked(_name));
224: bytes32 hashedName = keccak256(abi.encodePacked(_name));
238: bytes32 hashedName = keccak256(abi.encodePacked(_name));
Instances (3):
File: contracts/StabilityPod/SwingTraderManager.sol
99: _setupRole(STABILIZER_NODE_ROLE, _stabilizerNode);
File: contracts/Token/Malt.sol
112: _setupRole(MONETARY_MINTER_ROLE, minters[i]);
116: _setupRole(MONETARY_BURNER_ROLE, burners[i]);
Instances (1):
File: contracts/StabilityPod/ImpliedCollateralService.sol
46: ) StabilizedPoolUnit(timelock, repository, poolFactory) {}
Issue | Instances | |
---|---|---|
M-1 | Centralization Risk for trusted owners | 12 |
Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.
Instances (12):
File: contracts/Repository.sol
16: contract MaltRepository is AccessControl {
89: onlyRole(getRoleAdmin(role))
95: function addNewRole(bytes32 role) external onlyRole(TIMELOCK_ROLE) {
99: function removeRole(bytes32 role) external onlyRole(getRoleAdmin(role)) {
106: onlyRole(TIMELOCK_ROLE)
113: onlyRole(TIMELOCK_ROLE)
120: onlyRole(TIMELOCK_ROLE)
127: onlyRole(getRoleAdmin(role))
141: onlyRole(TIMELOCK_ROLE)
151: onlyRole(TIMELOCK_ROLE)
161: onlyRole(TIMELOCK_ROLE)
172: ) external onlyRole(TIMELOCK_ROLE) {