Skip to content

Instantly share code, notes, and snippets.

@Picodes
Last active January 6, 2023 20:32
Show Gist options
  • Save Picodes/ab2df52379e4b4993709be1b91aab651 to your computer and use it in GitHub Desktop.
Save Picodes/ab2df52379e4b4993709be1b91aab651 to your computer and use it in GitHub Desktop.

Report

Gas Optimizations

Issue Instances
GAS-1 Using bools for storage incurs overhead 17
GAS-2 Cache array length outside of loop 18
GAS-3 Use Custom Errors 202
GAS-4 Don't initialize variables with default value 66
GAS-5 Long revert strings 36
GAS-6 Functions guaranteed to revert when called by normal users can be marked payable 16
GAS-7 ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) 21
GAS-8 Using private rather than public for constants, saves gas 38
GAS-9 Use shift Right/Left instead of division/multiplication if possible 5
GAS-10 Use != 0 instead of > 0 for unsigned integer comparison 96

[GAS-1] Using bools for storage incurs overhead

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 (17):

File: mixins/Auth.sol

42:     bool public paused;
File: p1/BasketHandler.sol

139:     bool private disabled;
File: p1/Broker.sol

41:     bool public disabled;

44:     mapping(address => bool) private trades;
File: plugins/mocks/BadCollateralPlugin.sol

10:     bool public checkSoftDefault = true; // peg

11:     bool public checkHardDefault = true; // defi invariant
File: plugins/mocks/BadERC20.sol

13:     bool public revertDecimals;

15:     mapping(address => bool) public censored;
File: plugins/mocks/ERC1271Mock.sol

14:     bool public approvalsOn = false;
File: plugins/mocks/GnosisMockReentrant.sol

16:     bool public reenterOnInit;

17:     bool public reenterOnSettle;
File: plugins/mocks/InvalidBrokerMock.sol

20:     mapping(address => bool) private trades;

24:     bool public disabled = false;
File: plugins/mocks/InvalidChainlinkMock.sol

13:     bool public simplyRevert;
File: plugins/mocks/InvalidFiatCollateral.sol

9:     bool public simplyRevert;
File: plugins/mocks/RTokenCollateral.sol

31:     bool public priceable;
File: plugins/mocks/UnpricedAssetPlugin.sol

13:     bool public unpriced = false;

[GAS-2] Cache array length outside of loop

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 (18):

File: libraries/String.sol

14:         for (uint256 i = 0; i < bStr.length; i++) {
File: p1/BasketHandler.sol

218:         for (uint256 i = 0; i < config.erc20s.length; ++i) {

227:         for (uint256 i = 0; i < erc20s.length; ++i) {

262:         for (uint256 i = 0; i < erc20s.length; ++i) {

653:         for (uint256 i = 0; i < erc20s.length; i++) {

707:         for (uint256 i = 0; i < erc20s.length; ++i) {

725:         for (uint256 i = 0; i < erc20s.length; ++i) {
File: p1/Distributor.sol

108:         for (uint256 i = 0; i < destinations.length(); ++i) {
File: p1/RToken.sol

270:             for (uint256 i = 0; i < erc20s.length; ++i) {

711:         for (uint256 i = 0; i < queue.tokens.length; ++i) {
File: p1/mixins/RecollateralizationLib.sol

242:         for (uint256 i = 0; i < reg.erc20s.length; ++i) {

329:         for (uint256 i = 0; i < reg.erc20s.length; ++i) {
File: p1/mixins/RewardableLib.sol

27:         for (uint256 i = 0; i < registry.assets.length; ++i) {
File: plugins/mocks/EasyAuction.sol

277:             for (uint256 i = 0; i < _minBuyAmounts.length; i++) {

288:         for (uint256 i = 0; i < _minBuyAmounts.length; i++) {

316:         for (uint256 i = 0; i < _sellOrders.length; i++) {

513:         for (uint256 i = 0; i < orders.length; i++) {

524:         for (uint256 i = 0; i < orders.length; i++) {

[GAS-3] Use Custom Errors

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 (202):

File: libraries/RedemptionBattery.sol

44:         require(amount <= charge, "redemption battery insufficient");
File: mixins/Auth.sol

94:         require(account != address(0), "cannot grant role to address 0");

181:         require(shortFreeze_ > 0 && shortFreeze_ <= MAX_SHORT_FREEZE, "short freeze out of range");

188:         require(longFreeze_ > 0 && longFreeze_ <= MAX_LONG_FREEZE, "long freeze out of range");

197:         require(newUnfreezeAt > unfreezeAt, "frozen");
File: mixins/ComponentRegistry.sol

37:         require(address(val) != address(0), "invalid RToken address");

45:         require(address(val) != address(0), "invalid StRSR address");

53:         require(address(val) != address(0), "invalid AssetRegistry address");

61:         require(address(val) != address(0), "invalid BasketHandler address");

69:         require(address(val) != address(0), "invalid BackingManager address");

77:         require(address(val) != address(0), "invalid Distributor address");

85:         require(address(val) != address(0), "invalid RSRTrader address");

93:         require(address(val) != address(0), "invalid RTokenTrader address");

101:         require(address(val) != address(0), "invalid Furnace address");

109:         require(address(val) != address(0), "invalid Broker address");
File: p1/AssetRegistry.sol

74:         require(_erc20s.contains(address(asset.erc20())), "no ERC20 collision");

88:         require(_erc20s.contains(address(asset.erc20())), "no asset to unregister");

89:         require(assets[asset.erc20()] == asset, "asset not found");

103:         require(_erc20s.contains(address(erc20)), "erc20 unregistered");

111:         require(_erc20s.contains(address(erc20)), "erc20 unregistered");

112:         require(assets[erc20].isCollateral(), "erc20 is not collateral");
File: p1/BackingManager.sol

73:         require(assetRegistry.isRegistered(erc20), "erc20 unregistered");

85:         require(ArrayLib.allUnique(erc20s), "duplicate tokens");

97:         require(ArrayLib.sortedAndAllUnique(erc20s), "duplicate/unsorted tokens");

111:         require(basketHandler.status() == CollateralStatus.SOUND, "basket not sound");

257:         require(val <= MAX_TRADING_DELAY, "invalid tradingDelay");

264:         require(val <= MAX_BACKING_BUFFER, "invalid backingBuffer");
File: p1/BasketHandler.sol

168:         require(_msgSender() == address(assetRegistry), "asset registry only");

213:         require(erc20s.length > 0, "cannot empty basket");

214:         require(erc20s.length == targetAmts.length, "must be same length");

230:             require(assetRegistry.toAsset(erc20s[i]).isCollateral(), "token is not collateral");

231:             require(0 < targetAmts[i], "invalid target amount; must be nonzero");

232:             require(targetAmts[i] <= MAX_TARGET_AMT, "invalid target amount; too large");

265:             require(assetRegistry.toAsset(erc20s[i]).isCollateral(), "token is not collateral");

654:             require(erc20s[i] != rsr, "RSR is not valid collateral");

655:             require(erc20s[i] != IERC20(address(rToken)), "RToken is not valid collateral");

656:             require(erc20s[i] != IERC20(address(stRSR)), "stRSR is not valid collateral");

657:             require(erc20s[i] != zero, "address zero is not valid collateral");

660:         require(ArrayLib.allUnique(erc20s), "contains duplicates");
File: p1/Broker.sol

57:         require(address(gnosis_) != address(0), "invalid Gnosis address");

86:         require(!disabled, "broker disabled");

125:         require(trades[_msgSender()], "unrecognized trade contract");
File: p1/Deployer.sol

109:         require(owner != address(0) && owner != address(this), "invalid owner");
File: p1/Distributor.sol

92:         require(erc20 == rsr || erc20 == rToken, "RSR or RToken");

98:             require(totalShares > 0, "nothing to distribute");

162:         require(dest != address(0), "dest cannot be zero");

163:         if (dest == FURNACE) require(share.rsrDist == 0, "Furnace must get 0% of RSR");

164:         if (dest == ST_RSR) require(share.rTokenDist == 0, "StRSR must get 0% of RToken");

165:         require(share.rsrDist <= 10000, "RSR distribution too high");

166:         require(share.rTokenDist <= 10000, "RToken distribution too high");

172:             require(destinations.length() <= MAX_DESTINATIONS_ALLOWED, "Too many destinations");

182:         require(rTokenDist > 0 || rsrDist > 0, "no distribution defined");
File: p1/Furnace.sol

89:         require(period_ > 0 && period_ <= MAX_PERIOD, "invalid period");

97:         require(ratio_ <= MAX_RATIO, "invalid ratio");
File: p1/Main.sol

32:         require(address(rsr_) != address(0), "invalid RSR address");

48:         require(!pausedOrFrozen(), "paused or frozen");
File: p1/RToken.sol

156:         require(bytes(name_).length > 0, "name empty");

157:         require(bytes(symbol_).length > 0, "symbol empty");

158:         require(bytes(mandate_).length > 0, "mandate empty");

191:         require(amtRToken > 0, "Cannot issue zero");

217:         require(status == CollateralStatus.SOUND, "basket unsound");

384:         require(status == CollateralStatus.SOUND, "basket unsound");

410:         require(queue.left <= endId && endId <= queue.right, "out of range");

440:         require(amount > 0, "Cannot redeem zero");

448:         require(basketHandler.status() != CollateralStatus.DISABLED, "collateral default");

513:         if (allZero) revert("Empty redemption");

558:         require(_msgSender() == address(backingManager), "not backing manager");

581:         require(_msgSender() == address(backingManager), "not backing manager");

590:         require(val > 0 && val <= MAX_ISSUANCE_RATE, "invalid issuanceRate");

603:         require(val <= FIX_ONE, "invalid fraction");

623:         require(index >= item.left && index < item.right, "out of range");

705:             revert("Bad refundSpan");

741:         require(queue.left <= endId && endId <= queue.right, "out of range");

747:         require(rightItem.when <= FIX_ONE_256 * block.number, "issuance not ready");

813:         require(uint192(low) >= 1e9 && uint192(high) <= 1e27, "BU rate out of range");

833:         require(to != address(this), "RToken transfer to self");
File: p1/RevenueTrader.sol

29:         require(address(tokenToBuy_) != address(0), "invalid token address");

72:         require(buyPrice > 0 && buyPrice < FIX_MAX, "buy asset price unknown");
File: p1/StRSR.sol

168:         require(bytes(name_).length > 0, "name empty");

169:         require(bytes(symbol_).length > 0, "symbol empty");

213:         require(rsrAmount > 0, "Cannot stake zero");

259:         require(stakeAmount > 0, "Cannot withdraw zero");

260:         require(stakes[era][account] >= stakeAmount, "Not enough balance");

305:         require(basketHandler.fullyCollateralized(), "RToken uncollateralized");

306:         require(basketHandler.status() == CollateralStatus.SOUND, "basket defaulted");

312:         require(endId <= queue.length, "index out-of-bounds");

313:         require(queue[endId - 1].availableAt <= block.timestamp, "withdrawal unavailable");

375:         require(_msgSender() == address(backingManager), "not backing manager");

376:         require(rsrAmount > 0, "Amount cannot be zero");

380:         require(rsrAmount <= rsrBalance, "Cannot seize more RSR than we hold");

660:         require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");

675:         require(from != address(0), "ERC20: transfer from the zero address");

676:         require(to != address(0), "ERC20: transfer to the zero address");

680:         require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");

695:         require(account != address(0), "ERC20: mint to the zero address");

711:         require(account != address(0), "ERC20: burn from the zero address");

717:         require(accountBalance >= amount, "ERC20: burn amount exceeds balance");

732:         require(owner != address(0), "ERC20: approve from the zero address");

733:         require(spender != address(0), "ERC20: approve to the zero address");

746:             require(currentAllowance >= amount, "ERC20: insufficient allowance");

760:         require(to != address(this), "StRSR transfer to self");

775:         require(block.timestamp <= deadline, "ERC20Permit: expired deadline");

813:         require(val > 0 && val <= MAX_UNSTAKING_DELAY, "invalid unstakingDelay");

816:         require(rewardPeriod * 2 <= unstakingDelay, "unstakingDelay/rewardPeriod incompatible");

821:         require(val > 0 && val <= MAX_REWARD_PERIOD, "invalid rewardPeriod");

824:         require(rewardPeriod * 2 <= unstakingDelay, "unstakingDelay/rewardPeriod incompatible");

829:         require(val <= MAX_REWARD_RATIO, "invalid rewardRatio");
File: p1/StRSRVotes.sol

77:         require(blockNumber < block.number, "ERC20Votes: block not yet mined");

83:         require(blockNumber < block.number, "ERC20Votes: block not yet mined");

89:         require(blockNumber < block.number, "ERC20Votes: block not yet mined");

126:         require(block.timestamp <= expiry, "ERC20Votes: signature expired");

133:         require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
File: p1/mixins/Component.sol

34:         require(address(main_) != address(0), "main is zero address");

42:         require(!main.pausedOrFrozen(), "paused or frozen");

47:         require(!main.frozen(), "frozen");

52:         require(main.hasRole(OWNER, _msgSender()), "governance only");
File: p1/mixins/RewardableLib.sol

96:         require(reg.isRegistered(erc20), "erc20 unregistered");
File: p1/mixins/Trading.sol

69:         require(trade.canSettle(), "cannot settle yet");

129:         require(val < MAX_TRADE_SLIPPAGE, "invalid maxTradeSlippage");

136:         require(val <= MIN_TRADE_VOLUME, "invalid minTradeVolume");
File: plugins/aave/ERC20.sol

242:         require(sender != address(0), "ERC20: transfer from the zero address");

243:         require(recipient != address(0), "ERC20: transfer to the zero address");

262:         require(account != address(0), "ERC20: mint to the zero address");

283:         require(account != address(0), "ERC20: burn from the zero address");

310:         require(owner != address(0), "ERC20: approve from the zero address");

311:         require(spender != address(0), "ERC20: approve to the zero address");
File: plugins/aave/ReentrancyGuard.sol

51:         require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
File: plugins/assets/Asset.sol

48:         require(priceTimeout_ > 0, "price timeout zero");

49:         require(address(chainlinkFeed_) != address(0), "missing chainlink feed");

50:         require(oracleError_ > 0 && oracleError_ < FIX_ONE, "oracle error out of range");

51:         require(address(erc20_) != address(0), "missing erc20");

52:         require(maxTradeVolume_ > 0, "invalid max trade volume");

53:         require(oracleTimeout_ > 0, "oracleTimeout zero");
File: plugins/assets/CTokenFiatCollateral.sol

26:         require(address(comptroller_) != address(0), "comptroller missing");
File: plugins/assets/CTokenSelfReferentialCollateral.sol

29:         require(referenceERC20Decimals_ > 0, "referenceERC20Decimals missing");

30:         require(address(comptroller_) != address(0), "comptroller missing");
File: plugins/assets/EURFiatCollateral.sol

24:         require(address(uoaPerTargetFeed_) != address(0), "missing uoaPerTarget feed");
File: plugins/assets/FiatCollateral.sol

73:         require(config.targetName != bytes32(0), "targetName missing");

75:             require(config.delayUntilDefault > 0, "delayUntilDefault zero");
File: plugins/assets/NonFiatCollateral.sol

24:         require(address(uoaPerTargetFeed_) != address(0), "missing uoaPerTarget feed");
File: plugins/assets/RTokenAsset.sol

28:         require(address(erc20_) != address(0), "missing erc20");

29:         require(maxTradeVolume_ > 0, "invalid max trade volume");
File: plugins/assets/SelfReferentialCollateral.sol

19:         require(config.defaultThreshold == 0, "default threshold not supported");
File: plugins/governance/Governance.sol

102:         require(startedInSameEra(proposalId), "new era");

112:         require(!startedInSameEra(proposalId), "same era");

123:         require(startedInSameEra(proposalId), "new era");
File: plugins/mocks/BadERC20.sol

41:         if (censored[owner] || censored[to]) revert("censored");

54:         if (censored[from] || censored[to]) revert("censored");
File: plugins/mocks/EasyAuction.sol

131:         require(newFeeNumerator <= 15, "Fee is not allowed to be set higher than 1.5%");

164:         require(_auctionedSellAmount > 0, "cannot auction zero tokens");

165:         require(_minBuyAmount > 0, "tokens cannot be auctioned for free");

174:         require(auctionEndDate > block.timestamp, "auction end date must be in the future");

289:             require(_minBuyAmounts[i] > 0, "_minBuyAmounts must be greater than 0");

292:             require(_sellAmounts[i] > minimumBiddingAmountPerOrder, "order too small");

326:                 require(userIdOfIter == userId, "Only the user can cancel his orders");

350:         require(iterOrder != IterableOrderedOrderSet.QUEUE_END, "reached end of order list");

516:             require(sellOrders[auctionId].remove(orders[i]), "order is no longer claimable");

526:             require(userIdOrder == userId, "only allowed to claim for same user");

607:         require(registeredUsers.insert(numUsers, user), "User already registered");
File: plugins/mocks/GnosisMock.sol

69:         require(auctionedSellAmount > 0, "sell amount is zero");

91:         require(bid.sellAmount <= auctions[auctionId].sellAmount, "invalid bid sell");

92:         require(bid.buyAmount > 0, "zero volume bid");

100:         require(auction.endTime <= block.timestamp, "too early to close auction");

101:         require(auction.status == MauctionStatus.OPEN, "auction already closed");
File: plugins/mocks/GnosisMockReentrant.sol

33:         require(auctionedSellAmount > 0, "sell amount is zero");

61:         require(auction.endTime <= block.timestamp, "too early to close auction");

62:         require(auction.status == MauctionStatus.OPEN, "auction already closed");
File: plugins/mocks/InvalidATokenFiatCollateralMock.sol

11:         revert("claimRewards() error");
File: plugins/mocks/InvalidBrokerMock.sol

39:         require(!disabled, "broker disabled");

43:         revert("Failure opening trade");
File: plugins/mocks/InvalidFiatCollateral.sol

17:             revert("errormsg"); // Revert with no reason
File: plugins/mocks/RTokenCollateral.sol

43:         require(targetName_ != bytes32(0), "targetName missing");
File: plugins/mocks/upgrades/MainV2.sol

10:         require(!pausedOrFrozen(), "paused or frozen");
File: plugins/mocks/vendor/EasyAuction.sol

205:             require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");

258:         require(denominator != uint96(0), "Inserting zero is not supported");

362:         require(userIdLeft != userIdRight, "user is not allowed to place same order twice");

370:         require(!isEmpty(self), "Trying to get first from empty set");

375:         require(value != QUEUE_END, "Trying to get next of last element");

377:         require(nextElement != bytes32(0), "Trying to get next of non-existent element");

460:         require(c >= a, "SafeMath: addition overflow");

519:         require(c / a == b, "SafeMath: multiplication overflow");

623:         require(hasId(self, id), "Must have ID to get Address");

628:         require(hasAddress(self, addr), "Must have Address to get ID");

637:         require(addr != address(0), "Cannot insert zero address");

638:         require(id != uint64(-1), "Cannot insert max uint64");

657:         require(value < 2**96, "SafeCast: value doesn't fit in 96 bits");

662:         require(value < 2**64, "SafeCast: value doesn't fit in 64 bits");

718:         require(address(this).balance >= amount, "Address: insufficient balance");

722:         require(success, "Address: unable to send value, recipient may have reverted");

793:         require(address(this).balance >= value, "Address: insufficient balance for call");

794:         require(isContract(target), "Address: call to non-contract");

826:         require(isContract(target), "Address: static call to non-contract");

915:         require(_owner == _msgSender(), "Ownable: caller is not the owner");

936:         require(newOwner != address(0), "Ownable: new owner is the zero address");
File: plugins/trading/GnosisTrade.sol

60:         require(status == begin, "Invalid trade state");

88:         require(req.sellAmount <= type(uint96).max, "sellAmount too large");

89:         require(req.minBuyAmount <= type(uint96).max, "minBuyAmount too large");

95:         require(initBal <= type(uint96).max, "initBal too large");

96:         require(initBal >= req.sellAmount, "unfunded trade");

174:         require(msg.sender == origin, "only origin can settle");

216:         require(status == TradeStatus.CLOSED, "only after trade is closed");
File: vendor/ERC20PermitUpgradeable.sol

81:         require(block.timestamp <= deadline, "ERC20Permit: expired deadline");

[GAS-4] Don't initialize variables with default value

Instances (66):

File: libraries/Array.sol

12:             for (uint256 j = 0; j < i; ++j) {
File: libraries/Fixed.sol

50: uint192 constant FIX_ZERO = 0; // The uint192 representation of zero.

53: uint192 constant FIX_MIN = 0; // The smallest uint192.
File: libraries/String.sol

14:         for (uint256 i = 0; i < bStr.length; i++) {
File: p1/AssetRegistry.sol

38:         for (uint256 i = 0; i < length; ++i) {

49:         for (uint256 i = 0; i < length; ++i) {

127:         for (uint256 i = 0; i < length; ++i) {

138:         for (uint256 i = 0; i < length; ++i) {
File: p1/BackingManager.sol

221:         for (uint256 i = 0; i < length; ++i) {

238:         for (uint256 i = 0; i < length; ++i) {
File: p1/BasketHandler.sol

70:         for (uint256 i = 0; i < length; ++i) self.refAmts[self.erc20s[i]] = FIX_ZERO;

78:         for (uint256 i = 0; i < length; ++i) {

218:         for (uint256 i = 0; i < config.erc20s.length; ++i) {

227:         for (uint256 i = 0; i < erc20s.length; ++i) {

262:         for (uint256 i = 0; i < erc20s.length; ++i) {

286:         for (uint256 i = 0; i < size; ++i) {

337:         for (uint256 i = 0; i < len; ++i) {

397:         for (uint256 i = 0; i < len; ++i) {

416:         for (uint256 i = 0; i < length; ++i) {

437:         for (uint256 i = 0; i < length; ++i) {

530:         for (uint256 i = 0; i < basketLength; ++i) {

548:         for (uint256 i = 0; i < basketLength; ++i) {

586:         for (uint256 i = 0; i < targetsLength; ++i) {

592:             uint256 size = 0; // backup basket size

597:             for (uint256 j = 0; j < backupLength && size < backup.max; ++j) {

606:             uint256 assigned = 0;

611:             for (uint256 j = 0; j < backupLength && assigned < size; ++j) {

643:         for (uint256 i = 0; i < basketLength; ++i) {

653:         for (uint256 i = 0; i < erc20s.length; i++) {

707:         for (uint256 i = 0; i < erc20s.length; ++i) {

725:         for (uint256 i = 0; i < erc20s.length; ++i) {
File: p1/Distributor.sol

108:         for (uint256 i = 0; i < destinations.length(); ++i) {

133:         for (uint256 i = 0; i < numTransfers; i++) {

143:         for (uint256 i = 0; i < length; ++i) {
File: p1/RToken.sol

270:             for (uint256 i = 0; i < erc20s.length; ++i) {

303:             for (uint256 i = 0; i < basketSize; ++i) {

329:         for (uint256 i = 0; i < basketSize; ++i) {

334:         for (uint256 i = 0; i < basketSize; ++i) {

478:         for (uint256 i = 0; i < erc20length; ++i) {

501:         for (uint256 i = 0; i < erc20length; ++i) {

674:             for (uint256 i = 0; i < tokensLen; ++i) {

683:             for (uint256 i = 0; i < tokensLen; ++i) {

711:         for (uint256 i = 0; i < queue.tokens.length; ++i) {

757:             for (uint256 i = 0; i < tokensLen; ++i) {

767:             for (uint256 i = 0; i < tokensLen; ++i) {

793:         for (uint256 i = 0; i < tokensLen; ++i) {
File: p1/StRSRVotes.sol

102:         uint256 low = 0;
File: p1/mixins/RecollateralizationLib.sol

242:         for (uint256 i = 0; i < reg.erc20s.length; ++i) {

329:         for (uint256 i = 0; i < reg.erc20s.length; ++i) {

437:         for (uint256 i = 0; i < len; ++i) {
File: p1/mixins/RewardableLib.sol

27:         for (uint256 i = 0; i < registry.assets.length; ++i) {

67:         for (uint256 i = 0; i < erc20sLen; ++i) {

73:         for (uint256 i = 0; i < erc20sLen; ++i) {
File: plugins/mocks/ChainlinkMock.sol

17:     uint256 public constant override version = 0;
File: plugins/mocks/EasyAuction.sol

123:     uint256 public feeNumerator = 0;

277:             for (uint256 i = 0; i < _minBuyAmounts.length; i++) {

285:         uint256 sumOfSellAmounts = 0;

288:         for (uint256 i = 0; i < _minBuyAmounts.length; i++) {

315:         uint256 claimableAmount = 0;

316:         for (uint256 i = 0; i < _sellOrders.length; i++) {

344:         for (uint256 i = 0; i < iterationSteps; i++) {

513:         for (uint256 i = 0; i < orders.length; i++) {

524:         for (uint256 i = 0; i < orders.length; i++) {
File: plugins/mocks/GnosisMock.sol

50:     uint256 public constant feeNumerator = 0; // Does not support a fee
File: plugins/mocks/InvalidChainlinkMock.sol

51:         uint256 i = 0;
File: plugins/mocks/InvalidFiatCollateral.sol

32:         uint256 i = 0;

[GAS-5] Long revert strings

Instances (36):

File: p1/BasketHandler.sol

231:             require(0 < targetAmts[i], "invalid target amount; must be nonzero");

657:             require(erc20s[i] != zero, "address zero is not valid collateral");
File: p1/StRSR.sol

380:         require(rsrAmount <= rsrBalance, "Cannot seize more RSR than we hold");

660:         require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");

675:         require(from != address(0), "ERC20: transfer from the zero address");

676:         require(to != address(0), "ERC20: transfer to the zero address");

680:         require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");

711:         require(account != address(0), "ERC20: burn from the zero address");

717:         require(accountBalance >= amount, "ERC20: burn amount exceeds balance");

732:         require(owner != address(0), "ERC20: approve from the zero address");

733:         require(spender != address(0), "ERC20: approve to the zero address");

816:         require(rewardPeriod * 2 <= unstakingDelay, "unstakingDelay/rewardPeriod incompatible");

824:         require(rewardPeriod * 2 <= unstakingDelay, "unstakingDelay/rewardPeriod incompatible");
File: plugins/aave/ERC20.sol

242:         require(sender != address(0), "ERC20: transfer from the zero address");

243:         require(recipient != address(0), "ERC20: transfer to the zero address");

283:         require(account != address(0), "ERC20: burn from the zero address");

310:         require(owner != address(0), "ERC20: approve from the zero address");

311:         require(spender != address(0), "ERC20: approve to the zero address");
File: plugins/mocks/EasyAuction.sol

131:         require(newFeeNumerator <= 15, "Fee is not allowed to be set higher than 1.5%");

165:         require(_minBuyAmount > 0, "tokens cannot be auctioned for free");

174:         require(auctionEndDate > block.timestamp, "auction end date must be in the future");

289:             require(_minBuyAmounts[i] > 0, "_minBuyAmounts must be greater than 0");

326:                 require(userIdOfIter == userId, "Only the user can cancel his orders");

526:             require(userIdOrder == userId, "only allowed to claim for same user");
File: plugins/mocks/vendor/EasyAuction.sol

205:             require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");

362:         require(userIdLeft != userIdRight, "user is not allowed to place same order twice");

370:         require(!isEmpty(self), "Trying to get first from empty set");

375:         require(value != QUEUE_END, "Trying to get next of last element");

377:         require(nextElement != bytes32(0), "Trying to get next of non-existent element");

519:         require(c / a == b, "SafeMath: multiplication overflow");

657:         require(value < 2**96, "SafeCast: value doesn't fit in 96 bits");

662:         require(value < 2**64, "SafeCast: value doesn't fit in 64 bits");

722:         require(success, "Address: unable to send value, recipient may have reverted");

793:         require(address(this).balance >= value, "Address: insufficient balance for call");

826:         require(isContract(target), "Address: static call to non-contract");

936:         require(newOwner != address(0), "Ownable: new owner is the zero address");

[GAS-6] Functions guaranteed to revert when called by normal users can be marked 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.

Instances (16):

File: mixins/Auth.sol

65:     function __Auth_init(uint48 shortFreeze_, uint48 longFreeze_) internal onlyInitializing {

120:     function freezeShort() external onlyRole(SHORT_FREEZER) {

135:     function freezeLong() external onlyRole(LONG_FREEZER) {

148:     function freezeForever() external onlyRole(OWNER) {

157:     function unfreeze() external onlyRole(OWNER) {

165:     function pause() external onlyRole(PAUSER) {

172:     function unpause() external onlyRole(PAUSER) {

180:     function setShortFreeze(uint48 shortFreeze_) public onlyRole(OWNER) {

187:     function setLongFreeze(uint48 longFreeze_) public onlyRole(OWNER) {
File: mixins/ComponentRegistry.sol

19:     function __ComponentRegistry_init(Components memory components_) internal onlyInitializing {
File: p1/Main.sol

64:     function _authorizeUpgrade(address newImplementation) internal override onlyRole(OWNER) {}
File: p1/mixins/Component.sol

33:     function __Component_init(IMain main_) internal onlyInitializing {
File: plugins/mocks/vendor/EasyAuction.sol

926:     function renounceOwnership() public virtual onlyOwner {

935:     function transferOwnership(address newOwner) public virtual onlyOwner {
File: vendor/ERC20PermitUpgradeable.sol

61:     function __ERC20Permit_init(string memory name) internal onlyInitializing {

67:     function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}

[GAS-7] ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)

Saves 5 gas per loop

Instances (21):

File: libraries/Fixed.sol

165:             result++;

169:             result++;
File: libraries/String.sol

14:         for (uint256 i = 0; i < bStr.length; i++) {
File: p1/BasketHandler.sol

598:                 if (goodCollateral(_targetNames.at(i), backup.erc20s[j])) size++;

621:                     assigned++;

653:         for (uint256 i = 0; i < erc20s.length; i++) {
File: p1/Distributor.sol

128:             numTransfers++;

133:         for (uint256 i = 0; i < numTransfers; i++) {
File: p1/RToken.sol

316:         queue.right++;
File: p1/StRSR.sol

578:         era++;

590:         draftEra++;
File: p1/mixins/Trading.sol

121:         tradesOpen++;
File: plugins/mocks/ChainlinkMock.sol

39:         latestRound++;
File: plugins/mocks/EasyAuction.sol

277:             for (uint256 i = 0; i < _minBuyAmounts.length; i++) {

288:         for (uint256 i = 0; i < _minBuyAmounts.length; i++) {

316:         for (uint256 i = 0; i < _sellOrders.length; i++) {

344:         for (uint256 i = 0; i < iterationSteps; i++) {

513:         for (uint256 i = 0; i < orders.length; i++) {

524:         for (uint256 i = 0; i < orders.length; i++) {
File: plugins/mocks/InvalidChainlinkMock.sol

55:             i++;
File: plugins/mocks/InvalidFiatCollateral.sol

36:             i++;

[GAS-8] Using private rather than public for constants, saves gas

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 (38):

File: mixins/Auth.sol

27:     bytes32 public constant OWNER_ROLE = OWNER;

28:     bytes32 public constant SHORT_FREEZER_ROLE = SHORT_FREEZER;

29:     bytes32 public constant LONG_FREEZER_ROLE = LONG_FREEZER;

30:     bytes32 public constant PAUSER_ROLE = PAUSER;
File: p1/BackingManager.sol

33:     uint48 public constant MAX_TRADING_DELAY = 31536000; // {s} 1 year

34:     uint192 public constant MAX_BACKING_BUFFER = FIX_ONE; // {1} 100%
File: p1/BasketHandler.sol

117:     uint192 public constant MAX_TARGET_AMT = 1e3 * FIX_ONE; // {target/BU} max basket weight
File: p1/Broker.sol

24:     uint48 public constant MAX_AUCTION_LENGTH = 604800; // {s} max valid duration - 1 week
File: p1/Deployer.sol

31:     string public constant ENS = "reserveprotocol.eth";
File: p1/Distributor.sol

31:     address public constant FURNACE = address(1);

32:     address public constant ST_RSR = address(2);

34:     uint8 public constant MAX_DESTINATIONS_ALLOWED = 100;
File: p1/Furnace.sol

15:     uint192 public constant MAX_RATIO = FIX_ONE; // {1} 100%

16:     uint48 public constant MAX_PERIOD = 31536000; // {s} 1 year
File: p1/StRSR.sol

37:     uint48 public constant MAX_UNSTAKING_DELAY = 31536000; // {s} 1 year

38:     uint48 public constant MAX_REWARD_PERIOD = 31536000; // {s} 1 year

39:     uint192 public constant MAX_REWARD_RATIO = FIX_ONE; // {1} 100%

45:     uint8 public constant decimals = 18;
File: p1/mixins/Trading.sol

20:     uint192 public constant MIN_TRADE_VOLUME = 1e29; // {UoA}

21:     uint192 public constant MAX_TRADE_SLIPPAGE = 1e18; // {%}
File: plugins/aave/StaticATokenErrors.sol

5:     string public constant INVALID_OWNER = "1";

6:     string public constant INVALID_EXPIRATION = "2";

7:     string public constant INVALID_SIGNATURE = "3";

8:     string public constant INVALID_DEPOSITOR = "4";

9:     string public constant INVALID_RECIPIENT = "5";

10:     string public constant INVALID_CLAIMER = "6";

11:     string public constant ONLY_ONE_AMOUNT_FORMAT_ALLOWED = "7";
File: plugins/aave/StaticATokenLM.sol

40:     bytes public constant EIP712_REVISION = bytes("1");

45:     bytes32 public constant PERMIT_TYPEHASH =

49:     bytes32 public constant METADEPOSIT_TYPEHASH =

53:     bytes32 public constant METAWITHDRAWAL_TYPEHASH =

58:     uint256 public constant STATIC_ATOKEN_LM_REVISION = 0x1;
File: plugins/mocks/ChainlinkMock.sol

17:     uint256 public constant override version = 0;
File: plugins/mocks/EasyAuction.sol

124:     uint256 public constant FEE_DENOMINATOR = 1000;
File: plugins/mocks/GnosisMock.sol

50:     uint256 public constant feeNumerator = 0; // Does not support a fee
File: plugins/trading/GnosisTrade.sol

27:     uint256 public constant FEE_DENOMINATOR = 1000;

31:     uint96 public constant MAX_ORDERS = 1e5;

34:     uint192 public constant DEFAULT_MIN_BID = FIX_ONE / 100; // {tok}

[GAS-9] Use shift Right/Left instead of division/multiplication if possible

Instances (5):

File: libraries/Fixed.sol

164:         if (numerator % divisor > (divisor - 1) / 2) {

310:     uint64 constant FIX_HALF = uint64(FIX_SCALE) / 2;

323:             if (y & 1 == 1) result = (result * x + FIX_SCALE_SQ / 2) / FIX_SCALE_SQ;

326:             x = (x * x + FIX_SCALE_SQ / 2) / FIX_SCALE_SQ;

539:         if (mm > ((z - 1) / 2)) result += 1; // z should be z-1

[GAS-10] Use != 0 instead of > 0 for unsigned integer comparison

Instances (96):

File: libraries/Fixed.sol

101:     if (shiftLeft <= -96) return (rounding == CEIL ? 1 : 0); // 0 < uint.max / 10**77 < 0.5

102:     if (40 <= shiftLeft) revert UIntOutOfBounds(); // 10**56 < FIX_MAX < 10**57

168:         if (numerator % divisor > 0) {

537:         if (mm > 0) result += 1;
File: mixins/Auth.sol

45:        0 <= longFreeze[a] <= LONG_FREEZE_CHARGES for all addrs a

181:         require(shortFreeze_ > 0 && shortFreeze_ <= MAX_SHORT_FREEZE, "short freeze out of range");

188:         require(longFreeze_ > 0 && longFreeze_ <= MAX_LONG_FREEZE, "long freeze out of range");
File: p1/AssetRegistry.sol

78:         if (quantity > 0) basketHandler.disableBasket();

96:         if (quantity > 0) basketHandler.disableBasket();
File: p1/BackingManager.sol

109:         if (tradesOpen > 0) return;

173:         if (rsr.balanceOf(address(this)) > 0) {

200:                 uint192 rTok = (needed > 0) ? extraBUs.mulDiv(totalSupply, needed) : extraBUs;

240:             if (toRToken[i] > 0) erc20.safeTransfer(address(rTokenTrader), toRToken[i]);

241:             if (toRSR[i] > 0) erc20.safeTransfer(address(rsrTrader), toRSR[i]);
File: p1/BasketHandler.sol

213:         require(erc20s.length > 0, "cannot empty basket");

231:             require(0 < targetAmts[i], "invalid target amount; must be nonzero");

301:             if (refPerTok > 0) {

486:        If unsoundPrimeWt(tgt) > 0 and len(backups(tgt)) == 0 for some tgt, then disabled' == true.

523:         while (_targetNames.length() > 0) _targetNames.remove(_targetNames.at(0));

679:                 coll.refPerTok() > 0 &&

680:                 coll.targetPerRef() > 0;
File: p1/Broker.sol

135:             newAuctionLength > 0 && newAuctionLength <= MAX_AUCTION_LENGTH,
File: p1/Distributor.sol

98:             require(totalShares > 0, "nothing to distribute");

182:         require(rTokenDist > 0 || rsrDist > 0, "no distribution defined");

182:         require(rTokenDist > 0 || rsrDist > 0, "no distribution defined");
File: p1/Furnace.sol

83:         if (amount > 0) rToken.melt(amount);

89:         require(period_ > 0 && period_ <= MAX_PERIOD, "invalid period");
File: p1/RToken.sol

156:         require(bytes(name_).length > 0, "name empty");

157:         require(bytes(symbol_).length > 0, "symbol empty");

158:         require(bytes(mandate_).length > 0, "mandate empty");

191:         require(amtRToken > 0, "Cannot issue zero");

202:         if (queue.basketNonce > 0 && queue.basketNonce != basketNonce) {

234:             totalSupply() > 0 ? mulDiv256(basketsNeeded, amtRToken, totalSupply()) : amtRToken

295:         if (queue.right > 0) {

440:         require(amount > 0, "Cannot redeem zero");

483:             uint256 prorata = (prorate > 0)

590:         require(val > 0 && val <= MAX_ISSUANCE_RATE, "invalid issuanceRate");
File: p1/RevenueTrader.sol

72:         require(buyPrice > 0 && buyPrice < FIX_MAX, "buy asset price unknown");
File: p1/StRSR.sol

168:         require(bytes(name_).length > 0, "name empty");

169:         require(bytes(symbol_).length > 0, "symbol empty");

213:         require(rsrAmount > 0, "Cannot stake zero");

259:         require(stakeAmount > 0, "Cannot withdraw zero");

315:         uint192 oldDrafts = firstId > 0 ? queue[firstId - 1].drafts : 0;

376:         require(rsrAmount > 0, "Amount cannot be zero");

391:         if (stakeRSR > 0) {

406:         if (draftRSR > 0) {

504:         if (totalStakes > 0) {

559:         uint192 oldDrafts = index > 0 ? queue[index - 1].drafts : 0;

560:         uint64 lastAvailableAt = index > 0 ? queue[index - 1].availableAt : 0;

813:         require(val > 0 && val <= MAX_UNSTAKING_DELAY, "invalid unstakingDelay");

821:         require(val > 0 && val <= MAX_REWARD_PERIOD, "invalid rewardPeriod");
File: p1/StRSRVotes.sol

171:         if (src != dst && amount > 0) {

202:         if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {
File: p1/mixins/RecollateralizationLib.sol

411:                 high > 0 &&
File: p1/mixins/RewardableLib.sol

74:             if (deltas[i] > 0) {

98:         if (amt > 0) {
File: p1/mixins/TradeLib.sol

44:         assert(trade.buyPrice > 0 && trade.buyPrice < FIX_MAX && trade.sellPrice < FIX_MAX);

109:             trade.sellPrice > 0 &&

111:                 trade.buyPrice > 0 &&

183:         return size > 0 ? size : 1;

192:         return size > 0 ? size : 1;
File: plugins/aave/ReentrancyGuard.sol

3: pragma solidity >=0.6.0 <0.8.0;

3: pragma solidity >=0.6.0 <0.8.0;
File: plugins/aave/StaticATokenLM.sol

330:         if (staticAmount > 0) {

422:         if (supply > 0 && rewardsAccrued > 0) {

422:         if (supply > 0 && rewardsAccrued > 0) {

428:         if (rewardsAccrued > 0) {

461:         if (reward > 0) {

512:         if (balance > 0) {
File: plugins/assets/Asset.sol

48:         require(priceTimeout_ > 0, "price timeout zero");

50:         require(oracleError_ > 0 && oracleError_ < FIX_ONE, "oracle error out of range");

52:         require(maxTradeVolume_ > 0, "invalid max trade volume");

53:         require(oracleTimeout_ > 0, "oracleTimeout zero");
File: plugins/assets/CTokenSelfReferentialCollateral.sol

29:         require(referenceERC20Decimals_ > 0, "referenceERC20Decimals missing");
File: plugins/assets/FiatCollateral.sol

74:         if (config.defaultThreshold > 0) {

75:             require(config.delayUntilDefault > 0, "delayUntilDefault zero");
File: plugins/assets/RTokenAsset.sol

29:         require(maxTradeVolume_ > 0, "invalid max trade volume");
File: plugins/mocks/ATokenMock.sol

81:         if (address(aaveToken) != address(0) && aaveBalances[msg.sender] > 0) {
File: plugins/mocks/AaveLendingPoolMock.sol

36:         return _normalizedIncome[asset] > 0 ? _normalizedIncome[asset] : 1e27;
File: plugins/mocks/EasyAuction.sol

164:         require(_auctionedSellAmount > 0, "cannot auction zero tokens");

165:         require(_minBuyAmount > 0, "tokens cannot be auctioned for free");

167:             minimumBiddingAmountPerOrder > 0,

289:             require(_minBuyAmounts[i] > 0, "_minBuyAmounts must be greater than 0");

427:             currentBidSum > 0 &&

597:         if (auctioningTokenAmount > 0) {

600:         if (biddingTokenAmount > 0) {
File: plugins/mocks/GnosisMock.sol

69:         require(auctionedSellAmount > 0, "sell amount is zero");

92:         require(bid.buyAmount > 0, "zero volume bid");
File: plugins/mocks/GnosisMockReentrant.sol

33:         require(auctionedSellAmount > 0, "sell amount is zero");
File: plugins/mocks/WETH.sol

16: pragma solidity >=0.4.22 <0.6;
File: plugins/mocks/vendor/EasyAuction.sol

202:         if (returndata.length > 0) {

557:         require(b > 0, errorMessage);

698:         return size > 0;

842:             if (returndata.length > 0) {
File: plugins/trading/GnosisTrade.sol

191:         if (sellBal > 0) IERC20Upgradeable(address(sell)).safeTransfer(origin, sellBal);

192:         if (boughtAmt > 0) IERC20Upgradeable(address(buy)).safeTransfer(origin, boughtAmt);

Non Critical Issues

Issue Instances
NC-1 Return values of approve() not checked 12
NC-2 Constants should be defined rather than using magic numbers 3

[NC-1] Return values of approve() not checked

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 (12):

File: p1/StRSR.sol

633:         _approve(_msgSender(), spender, amount);

653:         _approve(owner, spender, _allowances[era][owner][spender] + addedValue);

662:             _approve(owner, spender, currentAllowance - subtractedValue);

748:                 _approve(owner, spender, currentAllowance - amount);

783:         _approve(owner, spender, value);
File: plugins/aave/ERC20.sol

143:         _approve(_msgSender(), spender, amount);

165:         _approve(

189:         _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));

212:         _approve(
File: plugins/aave/StaticATokenLM.sol

157:         _approve(owner, spender, value);
File: plugins/mocks/ERC20Mock.sol

23:         _approve(owner, spender, amount);
File: vendor/ERC20PermitUpgradeable.sol

93:         _approve(owner, spender, value);

[NC-2] Constants should be defined rather than using magic numbers

Instances (3):

File: libraries/Fixed.sol

102:     if (40 <= shiftLeft) revert UIntOutOfBounds(); // 10**56 < FIX_MAX < 10**57

213:         if (58 <= decimals) revert UIntOutOfBounds(); // 58, because x * 1e58 > 2 ** 192 if x != 0

390:         if (96 <= decimals) revert UIntOutOfBounds();

Low Issues

Issue Instances
L-1 Do not use deprecated library functions 10
L-2 Unsafe ERC20 operation(s) 1
L-3 Unspecific compiler version pragma 2

[L-1] Do not use deprecated library functions

Instances (10):

File: p1/BackingManager.sol

75:         IERC20Upgradeable(address(erc20)).safeApprove(address(main.rToken()), 0);

76:         IERC20Upgradeable(address(erc20)).safeApprove(address(main.rToken()), type(uint256).max);
File: p1/RevenueTrader.sol

61:             IERC20Upgradeable(address(erc20)).safeApprove(address(distributor), 0);

62:             IERC20Upgradeable(address(erc20)).safeApprove(address(distributor), bal);
File: p1/mixins/Trading.sol

116:         IERC20Upgradeable(address(sell)).safeApprove(address(broker), 0);

117:         IERC20Upgradeable(address(sell)).safeApprove(address(broker), req.sellAmount);
File: plugins/aave/StaticATokenLM.sol

101:         ASSET.safeApprove(address(pool), type(uint256).max);
File: plugins/mocks/vendor/EasyAuction.sol

144:     function safeApprove(
File: plugins/trading/GnosisTrade.sol

136:         IERC20Upgradeable(address(sell)).safeApprove(address(gnosis), 0);

137:         IERC20Upgradeable(address(sell)).safeApprove(address(gnosis), initBal);

[L-2] Unsafe ERC20 operation(s)

Instances (1):

File: plugins/mocks/WETH.sol

45:         msg.sender.transfer(wad);

[L-3] Unspecific compiler version pragma

Instances (2):

File: plugins/aave/ReentrancyGuard.sol

3: pragma solidity >=0.6.0 <0.8.0;
File: plugins/mocks/WETH.sol

16: pragma solidity >=0.4.22 <0.6;

Medium Issues

Issue Instances
M-1 Centralization Risk for trusted owners 21

[M-1] Centralization Risk for trusted owners

Impact:

Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.

Instances (21):

File: interfaces/IMain.sol

48: interface IAuth is IAccessControlUpgradeable {

149: interface IMain is IVersioned, IAuth, IComponentRegistry {
File: mixins/Auth.sol

16: abstract contract Auth is AccessControlUpgradeable, IAuth {

16: abstract contract Auth is AccessControlUpgradeable, IAuth {

92:         onlyRole(getRoleAdmin(role))

120:     function freezeShort() external onlyRole(SHORT_FREEZER) {

135:     function freezeLong() external onlyRole(LONG_FREEZER) {

148:     function freezeForever() external onlyRole(OWNER) {

157:     function unfreeze() external onlyRole(OWNER) {

165:     function pause() external onlyRole(PAUSER) {

172:     function unpause() external onlyRole(PAUSER) {

180:     function setShortFreeze(uint48 shortFreeze_) public onlyRole(OWNER) {

187:     function setLongFreeze(uint48 longFreeze_) public onlyRole(OWNER) {
File: mixins/ComponentRegistry.sol

13: abstract contract ComponentRegistry is Initializable, Auth, IComponentRegistry {
File: p1/Main.sol

18: contract MainP1 is Versioned, Initializable, Auth, ComponentRegistry, UUPSUpgradeable, IMain {

64:     function _authorizeUpgrade(address newImplementation) internal override onlyRole(OWNER) {}
File: plugins/mocks/EasyAuction.sol

8: contract EasyAuction is Ownable {

121:     constructor() public Ownable() {}
File: plugins/mocks/vendor/EasyAuction.sol

890: abstract contract Ownable is Context {

926:     function renounceOwnership() public virtual onlyOwner {

935:     function transferOwnership(address newOwner) public virtual onlyOwner {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment