Skip to content

Instantly share code, notes, and snippets.

@carlitox477
Last active October 4, 2023 20:55
Show Gist options
  • Save carlitox477/35963b3c46ebd25927c41ce368b8e10c to your computer and use it in GitHub Desktop.
Save carlitox477/35963b3c46ebd25927c41ce368b8e10c to your computer and use it in GitHub Desktop.
Reserve bot output

Report

Gas Optimizations

Issue Instances
GAS-1 Use assembly to check for address(0) 62
GAS-2 Using bools for storage incurs overhead 5
GAS-3 Cache array length outside of loop 26
GAS-4 State variables should be cached in stack variables rather than re-reading them from storage 13
GAS-5 Use calldata instead of memory for function arguments that do not get mutated 48
GAS-6 For Operations that will not overflow, you could use unchecked 1735
GAS-7 Use Custom Errors 163
GAS-8 Don't initialize variables with default value 52
GAS-9 Long revert strings 16
GAS-10 Functions guaranteed to revert when called by normal users can be marked payable 14
GAS-11 ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) 11
GAS-12 Using private rather than public for constants, saves gas 36
GAS-13 Use shift Right/Left instead of division/multiplication if possible 5
GAS-14 Splitting require() statements that use && saves gas 10
GAS-15 Use != 0 instead of > 0 for unsigned integer comparison 63
GAS-16 internal functions not called by the contract should be removed 29

[GAS-1] Use assembly to check for address(0)

Saves 6 gas per instance

Instances (62):

File: contracts/mixins/Auth.sol

92:         require(account != address(0), "cannot grant role to address 0");
File: contracts/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: contracts/p1/BasketHandler.sol

404:                 if (address(erc20) == address(0)) continue;
File: contracts/p1/Broker.sol

129:         require(address(newGnosis) != address(0), "invalid Gnosis address");

138:             address(newTradeImplementation) != address(0),

160:             address(newTradeImplementation) != address(0),
File: contracts/p1/Deployer.sol

49:             address(rsr_) != address(0) &&

50:                 address(gnosis_) != address(0) &&

51:                 address(rsrAsset_) != address(0) &&

52:                 address(implementations_.main) != address(0) &&

53:                 address(implementations_.trading.gnosisTrade) != address(0) &&

54:                 address(implementations_.trading.dutchTrade) != address(0) &&

55:                 address(implementations_.components.assetRegistry) != address(0) &&

56:                 address(implementations_.components.backingManager) != address(0) &&

57:                 address(implementations_.components.basketHandler) != address(0) &&

58:                 address(implementations_.components.broker) != address(0) &&

59:                 address(implementations_.components.distributor) != address(0) &&

60:                 address(implementations_.components.furnace) != address(0) &&

61:                 address(implementations_.components.rsrTrader) != address(0) &&

62:                 address(implementations_.components.rTokenTrader) != address(0) &&

63:                 address(implementations_.components.rToken) != address(0) &&

64:                 address(implementations_.components.stRSR) != address(0),

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

158:         require(dest != address(0), "dest cannot be zero");
File: contracts/p1/Main.sol

32:         require(address(rsr_) != address(0), "invalid RSR address");
File: contracts/p1/RevenueTrader.sol

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

111:         require(address(trades[erc20]) == address(0), "trade open");
File: contracts/p1/StRSR.sol

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

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

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

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

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

848:         require(spender != address(0), "ERC20: approve to the zero address");
File: contracts/p1/StRSRVotes.sol

144:         if (delegatee == address(0) && currentDelegate == address(0)) {

144:         if (delegatee == address(0) && currentDelegate == address(0)) {

147:         } else if (delegatee != address(0) && currentDelegate != delegatee) {

188:             if (src != address(0)) {

197:             if (dst != address(0)) {
File: contracts/p1/mixins/BasketLib.sol

293:         if (address(erc20) == address(0)) return false;
File: contracts/p1/mixins/Component.sol

34:         require(address(main_) != address(0), "main is zero address");
File: contracts/p1/mixins/RecollateralizationLib.sol

94:         if (address(trade.sell) == address(0) || address(trade.buy) == address(0)) {

94:         if (address(trade.sell) == address(0) || address(trade.buy) == address(0)) {

395:         if (address(trade.sell) == address(0) && address(trade.buy) != address(0)) {

395:         if (address(trade.sell) == address(0) && address(trade.buy) != address(0)) {
File: contracts/p1/mixins/Trading.sol

89:         require(address(trade) != address(0), "no trade open");

116:         assert(address(trades[sell]) == address(0));
File: contracts/plugins/trading/DutchTrade.sol

108:             address(sell_) != address(0) &&

109:                 address(buy_) != address(0) &&

147:         require(bidder == address(0), "bid already received");

177:         if (bidder != address(0)) {

203:         return status == TradeStatus.OPEN && (bidder != address(0) || block.timestamp > endTime);
File: contracts/plugins/trading/GnosisTrade.sol

92:         assert(origin_ != address(0));

225:         return data.clearingPriceOrder != bytes32(0);

[GAS-2] 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 (5):

File: contracts/mixins/Auth.sol

45:     bool public tradingPaused;

46:     bool public issuancePaused;
File: contracts/p1/BasketHandler.sol

51:     bool private disabled;
File: contracts/p1/Broker.sol

46:     bool public disabled;

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

[GAS-3] 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 (26):

File: contracts/libraries/String.sol

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

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

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

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

397:         for (uint48 i = 0; i < basketNonces.length; ++i) {

402:             for (uint256 j = 0; j < b.erc20s.length; ++j) {

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

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

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

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

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

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

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

264:         for (uint256 i = 0; i < portions.length; ++i) {

292:         for (uint256 i = 0; i < erc20sOut.length; ++i) {

306:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {

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

333:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {
File: contracts/p1/mixins/BasketLib.sol

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

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

248:             for (uint256 j = 0; j < backup.erc20s.length && size < backup.max; ++j) {

259:             for (uint256 j = 0; j < backup.erc20s.length && assigned < size; ++j) {
File: contracts/p1/mixins/RecollateralizationLib.sol

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

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

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

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

[GAS-4] 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 (13):

File: contracts/p1/BasketHandler.sol

515:             basketHistory[nonce].setFrom(_newBasket);
File: contracts/p1/RToken.sol

322:                     address(backingManager),

352:         _scaleUp(address(backingManager), baskets, totalSupply());

481:         emit BasketsNeededChanged(basketsNeeded, basketsNeeded + amtBaskets);
File: contracts/p1/RevenueTrader.sol

60:         tokenToBuy.safeApprove(address(distributor), bal);

95:         if (erc20 != IERC20(address(rToken)) && tokenToBuy != IERC20(address(rToken))) {

109:         IAsset buy = assetRegistry.toAsset(tokenToBuy);
File: contracts/p1/mixins/Trading.sol

119:         IERC20Upgradeable(address(sell)).safeApprove(address(broker), req.sellAmount);
File: contracts/plugins/trading/DutchTrade.sol

188:         buy.safeTransfer(address(origin), boughtAmt);
File: contracts/plugins/trading/GnosisTrade.sol

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

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

137:             endTime,

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

[GAS-5] Use calldata instead of memory for function arguments that do not get mutated

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

File: contracts/interfaces/IAssetRegistry.sol

34:     function init(IMain main_, IAsset[] memory assets_) external;
File: contracts/interfaces/IBasketHandler.sol

62:     function setPrimeBasket(IERC20[] memory erc20s, uint192[] memory targetAmts) external;

62:     function setPrimeBasket(IERC20[] memory erc20s, uint192[] memory targetAmts) external;

129:         uint48[] memory basketNonces,

130:         uint192[] memory portions,
File: contracts/interfaces/IBroker.sol

48:     function openTrade(TradeKind kind, TradeRequest memory req) external returns (ITrade);
File: contracts/interfaces/IDistributor.sol

40:     function init(IMain main_, RevenueShare memory dist) external;

43:     function setDistribution(address dest, RevenueShare memory share) external;
File: contracts/interfaces/IFacadeAct.sol

32:         IERC20[] memory toSettle,

33:         IERC20[] memory toStart,
File: contracts/interfaces/IGnosis.sol

37:         bytes memory accessManagerContractData
File: contracts/interfaces/IMain.sol

174:         Components memory components,
File: contracts/interfaces/IRToken.sol

63:         string memory name_,

64:         string memory symbol_,

65:         string memory mandate_,

106:         uint48[] memory basketNonces,

107:         uint192[] memory portions,

108:         address[] memory expectedERC20sOut,

109:         uint256[] memory minAmounts
File: contracts/interfaces/IStRSR.sol

103:         string memory name_,

104:         string memory symbol_,
File: contracts/libraries/test/ArrayCallerMock.sol

8:     function allUnique(IERC20[] memory arr) public pure returns (bool) {

12:     function sortedAndAllUnique(IERC20[] memory arr) public pure returns (bool) {
File: contracts/libraries/test/StringCallerMock.sol

9:     function toLower(string memory str) external pure returns (string memory){
File: contracts/p1/BasketHandler.sol

385:         uint48[] memory basketNonces,

386:         uint192[] memory portions,
File: contracts/p1/Broker.sol

97:     function openTrade(TradeKind kind, TradeRequest memory req) external returns (ITrade) {
File: contracts/p1/Deployer.sol

46:         Implementations memory implementations_

104:         string memory name,

105:         string memory symbol,

108:         DeploymentParams memory params
File: contracts/p1/Distributor.sol

61:     function setDistribution(address dest, RevenueShare memory share) external governance {
File: contracts/p1/Main.sol

27:         Components memory components,
File: contracts/p1/RToken.sol

248:         uint48[] memory basketNonces,

249:         uint192[] memory portions,

250:         address[] memory expectedERC20sOut,

251:         uint256[] memory minAmounts
File: contracts/p1/mixins/RecollateralizationLib.sol

58:     function prepareRecollateralizationTrade(IBackingManager bm, BasketRange memory basketsHeld)
File: contracts/plugins/governance/Governance.sol

94:         address[] memory targets,

95:         uint256[] memory values,

96:         bytes[] memory calldatas,

97:         string memory description

104:         address[] memory targets,

105:         uint256[] memory values,

106:         bytes[] memory calldatas,

114:         address[] memory targets,

115:         uint256[] memory values,

116:         bytes[] memory calldatas,

[GAS-6] For Operations that will not overflow, you could use unchecked

Instances (1735):

File: contracts/interfaces/IAsset.sol

4: import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

4: import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

4: import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

4: import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

4: import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

5: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

6: import "../libraries/Fixed.sol";

6: import "../libraries/Fixed.sol";

7: import "./IMain.sol";

8: import "./IRewardable.sol";

12:     uint192 low; // {UoA/tok}

12:     uint192 low; // {UoA/tok}

12:     uint192 low; // {UoA/tok}

13:     uint192 high; // {UoA/tok}

13:     uint192 high; // {UoA/tok}

13:     uint192 high; // {UoA/tok}

79:     IFFY, // When a peg is not holding or a chainlink feed is stale

79:     IFFY, // When a peg is not holding or a chainlink feed is stale

80:     DISABLED // When the collateral has completely defaulted

80:     DISABLED // When the collateral has completely defaulted
File: contracts/interfaces/IAssetRegistry.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "./IAsset.sol";

6: import "./IComponent.sol";
File: contracts/interfaces/IBackingManager.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "./IBroker.sol";

6: import "./IComponent.sol";

7: import "./ITrading.sol";
File: contracts/interfaces/IBasketHandler.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "../libraries/Fixed.sol";

5: import "../libraries/Fixed.sol";

6: import "./IAsset.sol";

7: import "./IComponent.sol";

10:     uint192 bottom; // {BU}

10:     uint192 bottom; // {BU}

11:     uint192 top; // {BU}

11:     uint192 top; // {BU}
File: contracts/interfaces/IBroker.sol

4: import "./IAsset.sol";

5: import "./IComponent.sol";

6: import "./IGnosis.sol";

7: import "./ITrade.sol";

18:     uint256 sellAmount; // {qSellTok}

18:     uint256 sellAmount; // {qSellTok}

19:     uint256 minBuyAmount; // {qBuyTok}

19:     uint256 minBuyAmount; // {qBuyTok}
File: contracts/interfaces/IComponent.sol

4: import "./IMain.sol";

5: import "./IVersioned.sol";
File: contracts/interfaces/IDeployer.sol

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "../libraries/Throttle.sol";

5: import "../libraries/Throttle.sol";

6: import "./IAsset.sol";

7: import "./IDistributor.sol";

8: import "./IGnosis.sol";

9: import "./IMain.sol";

10: import "./IRToken.sol";

11: import "./IStRSR.sol";

12: import "./ITrade.sol";

13: import "./IVersioned.sol";

22:     RevenueShare dist; // revenue sharing splits between RToken and RSR

22:     RevenueShare dist; // revenue sharing splits between RToken and RSR

25:     uint192 minTradeVolume; // {UoA}

25:     uint192 minTradeVolume; // {UoA}

26:     uint192 rTokenMaxTradeVolume; // {UoA}

26:     uint192 rTokenMaxTradeVolume; // {UoA}

29:     uint48 shortFreeze; // {s} how long an initial freeze lasts

29:     uint48 shortFreeze; // {s} how long an initial freeze lasts

30:     uint48 longFreeze; // {s} how long each freeze extension lasts

30:     uint48 longFreeze; // {s} how long each freeze extension lasts

33:     uint192 rewardRatio; // the fraction of available revenues that are paid out each 12s period

33:     uint192 rewardRatio; // the fraction of available revenues that are paid out each 12s period

36:     uint48 unstakingDelay; // {s} the "thawing time" of staked RSR before withdrawal

36:     uint48 unstakingDelay; // {s} the "thawing time" of staked RSR before withdrawal

37:     uint192 withdrawalLeak; // {1} fraction of RSR that can be withdrawn without refresh

37:     uint192 withdrawalLeak; // {1} fraction of RSR that can be withdrawn without refresh

40:     uint48 warmupPeriod; // {s} how long to wait until issuance/trading after regaining SOUND

40:     uint48 warmupPeriod; // {s} how long to wait until issuance/trading after regaining SOUND

40:     uint48 warmupPeriod; // {s} how long to wait until issuance/trading after regaining SOUND

43:     uint48 tradingDelay; // {s} how long to wait until starting auctions after switching basket

43:     uint48 tradingDelay; // {s} how long to wait until starting auctions after switching basket

44:     uint48 batchAuctionLength; // {s} the length of a Gnosis EasyAuction

44:     uint48 batchAuctionLength; // {s} the length of a Gnosis EasyAuction

45:     uint48 dutchAuctionLength; // {s} the length of a falling-price dutch auction

45:     uint48 dutchAuctionLength; // {s} the length of a falling-price dutch auction

45:     uint48 dutchAuctionLength; // {s} the length of a falling-price dutch auction

46:     uint192 backingBuffer; // {1} how much extra backing collateral to keep

46:     uint192 backingBuffer; // {1} how much extra backing collateral to keep

47:     uint192 maxTradeSlippage; // {1} max slippage acceptable in a trade

47:     uint192 maxTradeSlippage; // {1} max slippage acceptable in a trade

50:     ThrottleLib.Params issuanceThrottle; // see ThrottleLib

50:     ThrottleLib.Params issuanceThrottle; // see ThrottleLib
File: contracts/interfaces/IDeployerRegistry.sol

4: import "./IDeployer.sol";
File: contracts/interfaces/IDistributor.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "./IComponent.sol";

7: uint256 constant MAX_DISTRIBUTION = 1e4; // 10,000

7: uint256 constant MAX_DISTRIBUTION = 1e4; // 10,000

8: uint8 constant MAX_DESTINATIONS = 100; // maximum number of RevenueShare destinations

8: uint8 constant MAX_DESTINATIONS = 100; // maximum number of RevenueShare destinations

11:     uint16 rTokenDist; // {revShare} A value between [0, 10,000]

11:     uint16 rTokenDist; // {revShare} A value between [0, 10,000]

12:     uint16 rsrDist; // {revShare} A value between [0, 10,000]

12:     uint16 rsrDist; // {revShare} A value between [0, 10,000]

17:     uint24 rTokenTotal; // {revShare}

17:     uint24 rTokenTotal; // {revShare}

18:     uint24 rsrTotal; // {revShare}

18:     uint24 rsrTotal; // {revShare}
File: contracts/interfaces/IFacadeAct.sol

4: import "../interfaces/IBackingManager.sol";

4: import "../interfaces/IBackingManager.sol";

5: import "../interfaces/IRevenueTrader.sol";

5: import "../interfaces/IRevenueTrader.sol";

6: import "../interfaces/IRToken.sol";

6: import "../interfaces/IRToken.sol";

15: v */

15: v */
File: contracts/interfaces/IFacadeRead.sol

4: import "../p1/RToken.sol";

4: import "../p1/RToken.sol";

5: import "./IRToken.sol";

6: import "./IStRSR.sol";

13: v */

13: v */
File: contracts/interfaces/IFacadeTest.sol

4: import "./IRToken.sol";

5: import "./IStRSR.sol";
File: contracts/interfaces/IFacadeWrite.sol

4: import "./IDeployer.sol";

59:     uint256 votingDelay; // in blocks

59:     uint256 votingDelay; // in blocks

60:     uint256 votingPeriod; // in blocks

60:     uint256 votingPeriod; // in blocks

61:     uint256 proposalThresholdAsMicroPercent; // e.g. 1e4 for 0.01%

61:     uint256 proposalThresholdAsMicroPercent; // e.g. 1e4 for 0.01%

62:     uint256 quorumPercent; // e.g 4 for 4%

62:     uint256 quorumPercent; // e.g 4 for 4%

63:     uint256 timelockDelay; // in seconds (used for timelock)

63:     uint256 timelockDelay; // in seconds (used for timelock)
File: contracts/interfaces/IFurnace.sol

4: import "../libraries/Fixed.sol";

4: import "../libraries/Fixed.sol";

5: import "./IComponent.sol";
File: contracts/interfaces/IGnosis.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
File: contracts/interfaces/IMain.sol

4: import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "./IAssetRegistry.sol";

7: import "./IBasketHandler.sol";

8: import "./IBackingManager.sol";

9: import "./IBroker.sol";

10: import "./IGnosis.sol";

11: import "./IFurnace.sol";

12: import "./IDistributor.sol";

13: import "./IRToken.sol";

14: import "./IRevenueTrader.sol";

15: import "./IStRSR.sol";

16: import "./ITrading.sol";

17: import "./IVersioned.sol";

21: uint48 constant ONE_BLOCK = 12; //{s}

21: uint48 constant ONE_BLOCK = 12; //{s}

167:     function poke() external; // not used in p1

167:     function poke() external; // not used in p1
File: contracts/interfaces/IRToken.sol

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

7: import "../libraries/Fixed.sol";

7: import "../libraries/Fixed.sol";

8: import "../libraries/Throttle.sol";

8: import "../libraries/Throttle.sol";

9: import "./IAsset.sol";

10: import "./IComponent.sol";

11: import "./IMain.sol";

12: import "./IRewardable.sol";
File: contracts/interfaces/IRevenueTrader.sol

4: import "./IBroker.sol";

5: import "./IComponent.sol";

6: import "./ITrading.sol";
File: contracts/interfaces/IRewardable.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "./IComponent.sol";

6: import "./IMain.sol";
File: contracts/interfaces/IStRSR.sol

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol";

7: import "../libraries/Fixed.sol";

7: import "../libraries/Fixed.sol";

8: import "./IComponent.sol";

9: import "./IMain.sol";
File: contracts/interfaces/IStRSRVotes.sol

4: import "@openzeppelin/contracts-upgradeable/governance/utils/IVotesUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/governance/utils/IVotesUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/governance/utils/IVotesUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/governance/utils/IVotesUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/governance/utils/IVotesUpgradeable.sol";
File: contracts/interfaces/ITrade.sol

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "./IBroker.sol";

8:     NOT_STARTED, // before init()

8:     NOT_STARTED, // before init()

9:     OPEN, // after init() and before settle()

9:     OPEN, // after init() and before settle()

10:     CLOSED, // after settle()

10:     CLOSED, // after settle()

12:     PENDING // during init() or settle() (reentrancy protection)

12:     PENDING // during init() or settle() (reentrancy protection)
File: contracts/interfaces/ITrading.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "../libraries/Fixed.sol";

5: import "../libraries/Fixed.sol";

6: import "./IAsset.sol";

7: import "./IComponent.sol";

8: import "./ITrade.sol";

9: import "./IRewardable.sol";
File: contracts/libraries/Array.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

11:         for (uint256 i = 1; i < arrLen; ++i) {

11:         for (uint256 i = 1; i < arrLen; ++i) {

12:             for (uint256 j = 0; j < i; ++j) {

12:             for (uint256 j = 0; j < i; ++j) {

23:         for (uint256 i = 1; i < arrLen; ++i) {

23:         for (uint256 i = 1; i < arrLen; ++i) {

24:             if (uint160(address(arr[i])) <= uint160(address(arr[i - 1]))) return false;
File: contracts/libraries/Fixed.sol

10:     "fixed192x18" -- a value represented by 192 bits, that makes 18 digits available to

10:     "fixed192x18" -- a value represented by 192 bits, that makes 18 digits available to

13:     The range of values that uint192 can represent is about [-1.7e20, 1.7e20].

48: uint192 constant FIX_MAX_INT = type(uint192).max / FIX_SCALE;

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

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

51: uint192 constant FIX_ONE = FIX_SCALE; // The uint192 representation of one.

51: uint192 constant FIX_ONE = FIX_SCALE; // The uint192 representation of one.

52: uint192 constant FIX_MAX = type(uint192).max; // The largest uint192. (Not an integer!)

52: uint192 constant FIX_MAX = type(uint192).max; // The largest uint192. (Not an integer!)

53: uint192 constant FIX_MIN = 0; // The smallest uint192.

53: uint192 constant FIX_MIN = 0; // The smallest uint192.

57:     FLOOR, // Round towards zero

57:     FLOOR, // Round towards zero

58:     ROUND, // Round to the nearest int

58:     ROUND, // Round to the nearest int

59:     CEIL // Round away from zero

59:     CEIL // Round away from zero

67:    Thus, all the tedious-looking double conversions like uint256(uint256 (foo))

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

68:    See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions

81:     return _safeWrap(x * FIX_SCALE);

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

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

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

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

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

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

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

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

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

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

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

104:     shiftLeft += 18;

106:     uint256 coeff = 10**abs(shiftLeft);

106:     uint256 coeff = 10**abs(shiftLeft);

107:     uint256 shifted = (shiftLeft >= 0) ? x * coeff : _divrnd(x, coeff, rounding);

119:     if (x < uint256(type(uint256).max / FIX_SCALE_SQ)) {

120:         return _safeWrap(uint256(x * FIX_SCALE_SQ) / y);

120:         return _safeWrap(uint256(x * FIX_SCALE_SQ) / y);

148:     return x < 0 ? uint256(-x) : uint256(x);

159:     uint256 result = numerator / divisor;

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

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

165:             result++;

165:             result++;

169:             result++;

169:             result++;

212:         if (decimals <= -59) return (rounding == CEIL ? 1 : 0); // 59, because 1e58 > 2**192

212:         if (decimals <= -59) return (rounding == CEIL ? 1 : 0); // 59, because 1e58 > 2**192

212:         if (decimals <= -59) return (rounding == CEIL ? 1 : 0); // 59, because 1e58 > 2**192

212:         if (decimals <= -59) return (rounding == CEIL ? 1 : 0); // 59, because 1e58 > 2**192

212:         if (decimals <= -59) return (rounding == CEIL ? 1 : 0); // 59, because 1e58 > 2**192

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

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

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

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

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

215:         uint256 coeff = uint256(10**abs(decimals));

215:         uint256 coeff = uint256(10**abs(decimals));

216:         return _safeWrap(decimals >= 0 ? x * coeff : _divrnd(x, coeff, rounding));

223:         return x + y;

230:         return _safeWrap(x + y * FIX_SCALE);

230:         return _safeWrap(x + y * FIX_SCALE);

237:         return x - y;

244:         return _safeWrap(uint256(x) - uint256(y * FIX_SCALE));

244:         return _safeWrap(uint256(x) - uint256(y * FIX_SCALE));

263:         return _safeWrap(_divrnd(uint256(x) * uint256(y), FIX_SCALE, rounding));

270:         return _safeWrap(x * y);

289:         return _safeWrap(_divrnd(uint256(x) * FIX_SCALE, y, rounding));

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

320:         uint256 x = uint256(x_) * FIX_SCALE; // x is D36

320:         uint256 x = uint256(x_) * FIX_SCALE; // x is D36

320:         uint256 x = uint256(x_) * FIX_SCALE; // x is D36

321:         uint256 result = FIX_SCALE_SQ; // result is D36

321:         uint256 result = FIX_SCALE_SQ; // result is D36

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

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

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

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;

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

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

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

328:         return _safeWrap(result / FIX_SCALE);

364:         uint192 diff = x <= y ? y - x : x - y;

364:         uint192 diff = x <= y ? y - x : x - y;

388:         if (x == 0) return 0; // always computable, no matter what decimals is

388:         if (x == 0) return 0; // always computable, no matter what decimals is

389:         if (decimals <= -42) return (rounding == CEIL ? 1 : 0);

392:         decimals -= 18; // shift so that toUint happens at the same time.

392:         decimals -= 18; // shift so that toUint happens at the same time.

392:         decimals -= 18; // shift so that toUint happens at the same time.

394:         uint256 coeff = uint256(10**abs(decimals));

394:         uint256 coeff = uint256(10**abs(decimals));

395:         return decimals >= 0 ? uint256(x * coeff) : uint256(_divrnd(x, coeff, rounding));

504:             uint256 rawDelta = uint256(b) * a; // {D36} = {D18} * {D18}

504:             uint256 rawDelta = uint256(b) * a; // {D36} = {D18} * {D18}

504:             uint256 rawDelta = uint256(b) * a; // {D36} = {D18} * {D18}

504:             uint256 rawDelta = uint256(b) * a; // {D36} = {D18} * {D18}

506:             if (rawDelta / b != a) return FIX_MAX;

510:             if (rounding == RoundingMode.ROUND) shiftDelta += (FIX_ONE / 2);

510:             if (rounding == RoundingMode.ROUND) shiftDelta += (FIX_ONE / 2);

511:             else if (rounding == RoundingMode.CEIL) shiftDelta += FIX_ONE - 1;

511:             else if (rounding == RoundingMode.CEIL) shiftDelta += FIX_ONE - 1;

529:             if (shiftDelta / FIX_ONE > FIX_MAX) return FIX_MAX;

532:             return uint192(shiftDelta / FIX_ONE); // {D18} = {D36} / {D18}

532:             return uint192(shiftDelta / FIX_ONE); // {D18} = {D36} / {D18}

532:             return uint192(shiftDelta / FIX_ONE); // {D18} = {D36} / {D18}

532:             return uint192(shiftDelta / FIX_ONE); // {D18} = {D36} / {D18}

556:         if (mm > lo) hi -= 1;

557:         lo -= mm;

558:         uint256 pow2 = z & (0 - z);

559:         z /= pow2;

560:         lo /= pow2;

561:         lo += hi * ((0 - pow2) / pow2 + 1);

561:         lo += hi * ((0 - pow2) / pow2 + 1);

561:         lo += hi * ((0 - pow2) / pow2 + 1);

561:         lo += hi * ((0 - pow2) / pow2 + 1);

561:         lo += hi * ((0 - pow2) / pow2 + 1);

563:         r *= 2 - z * r;

563:         r *= 2 - z * r;

563:         r *= 2 - z * r;

564:         r *= 2 - z * r;

564:         r *= 2 - z * r;

564:         r *= 2 - z * r;

565:         r *= 2 - z * r;

565:         r *= 2 - z * r;

565:         r *= 2 - z * r;

566:         r *= 2 - z * r;

566:         r *= 2 - z * r;

566:         r *= 2 - z * r;

567:         r *= 2 - z * r;

567:         r *= 2 - z * r;

567:         r *= 2 - z * r;

568:         r *= 2 - z * r;

568:         r *= 2 - z * r;

568:         r *= 2 - z * r;

569:         r *= 2 - z * r;

569:         r *= 2 - z * r;

569:         r *= 2 - z * r;

570:         r *= 2 - z * r;

570:         r *= 2 - z * r;

570:         r *= 2 - z * r;

571:         result = lo * r;

589:         if (mm > 0) result += 1;

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

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

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

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

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

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

604:         uint256 mm = mulmod(x, y, uint256(0) - uint256(1));

605:         lo = x * y;

606:         hi = mm - lo;

607:         if (mm < lo) hi -= 1;
File: contracts/libraries/Permit.sol

4: import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";
File: contracts/libraries/String.sol

14:         for (uint256 i = 0; i < bStr.length; i++) {

14:         for (uint256 i = 0; i < bStr.length; i++) {

18:                 bLower[i] = bytes1(uint8(bStr[i]) + 32);
File: contracts/libraries/Throttle.sol

4: import "./Fixed.sol";

6: uint48 constant ONE_HOUR = 3600; // {seconds/hour}

6: uint48 constant ONE_HOUR = 3600; // {seconds/hour}

6: uint48 constant ONE_HOUR = 3600; // {seconds/hour}

21:         uint256 amtRate; // {qRTok/hour} a quantity of RToken hourly; cannot be 0

21:         uint256 amtRate; // {qRTok/hour} a quantity of RToken hourly; cannot be 0

21:         uint256 amtRate; // {qRTok/hour} a quantity of RToken hourly; cannot be 0

22:         uint192 pctRate; // {1/hour} a fraction of RToken hourly; can be 0

22:         uint192 pctRate; // {1/hour} a fraction of RToken hourly; can be 0

22:         uint192 pctRate; // {1/hour} a fraction of RToken hourly; can be 0

29:         uint48 lastTimestamp; // {seconds}

29:         uint48 lastTimestamp; // {seconds}

30:         uint256 lastAvailable; // {qRTok}

30:         uint256 lastAvailable; // {qRTok}

46:         uint256 limit = hourlyLimit(throttle, supply); // {qRTok}

46:         uint256 limit = hourlyLimit(throttle, supply); // {qRTok}

54:             available -= uint256(amount);

57:             available += uint256(-amount);

57:             available += uint256(-amount);

72:         uint48 delta = uint48(block.timestamp) - throttle.lastTimestamp; // {seconds}

72:         uint48 delta = uint48(block.timestamp) - throttle.lastTimestamp; // {seconds}

72:         uint48 delta = uint48(block.timestamp) - throttle.lastTimestamp; // {seconds}

73:         available = throttle.lastAvailable + (limit * delta) / ONE_HOUR;

73:         available = throttle.lastAvailable + (limit * delta) / ONE_HOUR;

73:         available = throttle.lastAvailable + (limit * delta) / ONE_HOUR;

86:         limit = (supply * params.pctRate) / FIX_ONE_256; // {qRTok}

86:         limit = (supply * params.pctRate) / FIX_ONE_256; // {qRTok}

86:         limit = (supply * params.pctRate) / FIX_ONE_256; // {qRTok}

86:         limit = (supply * params.pctRate) / FIX_ONE_256; // {qRTok}
File: contracts/libraries/test/ArrayCallerMock.sol

4: import "../Array.sol";
File: contracts/libraries/test/FixedCallerMock.sol

4: import "../Fixed.sol";
File: contracts/libraries/test/StringCallerMock.sol

4: import "../String.sol";
File: contracts/mixins/Auth.sol

4: import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

5: import "../interfaces/IMain.sol";

5: import "../interfaces/IMain.sol";

7: uint256 constant LONG_FREEZE_CHARGES = 6; // 6 uses

7: uint256 constant LONG_FREEZE_CHARGES = 6; // 6 uses

9: uint48 constant MAX_SHORT_FREEZE = 2592000; // 1 month

9: uint48 constant MAX_SHORT_FREEZE = 2592000; // 1 month

10: uint48 constant MAX_LONG_FREEZE = 31536000; // 1 year

10: uint48 constant MAX_LONG_FREEZE = 31536000; // 1 year

38:     uint48 public unfreezeAt; // {s} uint48.max to pause indefinitely

38:     uint48 public unfreezeAt; // {s} uint48.max to pause indefinitely

39:     uint48 public shortFreeze; // {s} length of an initial freeze

39:     uint48 public shortFreeze; // {s} length of an initial freeze

40:     uint48 public longFreeze; // {s} length of a freeze extension

40:     uint48 public longFreeze; // {s} length of a freeze extension

127:         freezeUntil(uint48(block.timestamp) + shortFreeze);

140:         longFreezes[_msgSender()] -= 1; // reverts on underflow

140:         longFreezes[_msgSender()] -= 1; // reverts on underflow

140:         longFreezes[_msgSender()] -= 1; // reverts on underflow

144:         freezeUntil(uint48(block.timestamp) + longFreeze);
File: contracts/mixins/ComponentRegistry.sol

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

7: import "../interfaces/IMain.sol";

7: import "../interfaces/IMain.sol";

8: import "./Auth.sol";
File: contracts/mixins/Versioned.sol

4: import "../interfaces/IVersioned.sol";

4: import "../interfaces/IVersioned.sol";
File: contracts/p1/AssetRegistry.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

6: import "../interfaces/IAssetRegistry.sol";

6: import "../interfaces/IAssetRegistry.sol";

7: import "../interfaces/IMain.sol";

7: import "../interfaces/IMain.sol";

8: import "./mixins/Component.sol";

8: import "./mixins/Component.sol";

15:     uint256 public constant GAS_TO_RESERVE = 900000; // just enough to disable basket on n=128

15:     uint256 public constant GAS_TO_RESERVE = 900000; // just enough to disable basket on n=128

29:     uint48 public lastRefresh; // {s}

29:     uint48 public lastRefresh; // {s}

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

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

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

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

64:         lastRefresh = uint48(block.timestamp); // safer to do this at end than start, actually

64:         lastRefresh = uint48(block.timestamp); // safer to do this at end than start, actually

90:             if (quantity > 0) basketHandler.disableBasket(); // not an interaction

90:             if (quantity > 0) basketHandler.disableBasket(); // not an interaction

107:             if (quantity > 0) basketHandler.disableBasket(); // not an interaction

107:             if (quantity > 0) basketHandler.disableBasket(); // not an interaction

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

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

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

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

211:         return gas - GAS_TO_RESERVE;
File: contracts/p1/BackingManager.sol

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "../interfaces/IAsset.sol";

6: import "../interfaces/IAsset.sol";

7: import "../interfaces/IBackingManager.sol";

7: import "../interfaces/IBackingManager.sol";

8: import "../interfaces/IMain.sol";

8: import "../interfaces/IMain.sol";

9: import "../libraries/Array.sol";

9: import "../libraries/Array.sol";

10: import "../libraries/Fixed.sol";

10: import "../libraries/Fixed.sol";

11: import "./mixins/Trading.sol";

11: import "./mixins/Trading.sol";

12: import "./mixins/RecollateralizationLib.sol";

12: import "./mixins/RecollateralizationLib.sol";

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

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

34:     uint192 public constant MAX_BACKING_BUFFER = FIX_ONE; // {1} 100%

34:     uint192 public constant MAX_BACKING_BUFFER = FIX_ONE; // {1} 100%

36:     uint48 public tradingDelay; // {s} how long to wait until resuming trading after switching

36:     uint48 public tradingDelay; // {s} how long to wait until resuming trading after switching

37:     uint192 public backingBuffer; // {1} how much extra backing collateral to keep

37:     uint192 public backingBuffer; // {1} how much extra backing collateral to keep

41:     mapping(TradeKind => uint48) private tradeEnd; // {s} last endTime() of an auction per kind

41:     mapping(TradeKind => uint48) private tradeEnd; // {s} last endTime() of an auction per kind

84:         trade = super.settleTrade(sell); // nonReentrant

84:         trade = super.settleTrade(sell); // nonReentrant

94:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

94:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

94:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

94:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

94:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

112:             _msgSender() == address(this) || tradeEnd[kind] + ONE_BLOCK < block.timestamp,

118:         require(block.timestamp >= basketHandler.timestamp() + tradingDelay, "trading delayed");

127:         if (balance >= MAX_DISTRIBUTION * MAX_DESTINATIONS) main.rToken().dissolve(balance);

128:         if (basketsHeld.bottom >= rToken.basketsNeeded()) return; // return if now capitalized

128:         if (basketsHeld.bottom >= rToken.basketsNeeded()) return; // return if now capitalized

151:                 if (req.sellAmount > bal) stRSR.seizeRSR(req.sellAmount - bal);

182:         require(block.timestamp >= basketHandler.timestamp() + tradingDelay, "trading delayed");

212:         uint192 needed = rToken.basketsNeeded().mul(FIX_ONE + backingBuffer); // {BU}

212:         uint192 needed = rToken.basketsNeeded().mul(FIX_ONE + backingBuffer); // {BU}

212:         uint192 needed = rToken.basketsNeeded().mul(FIX_ONE + backingBuffer); // {BU}

214:             rToken.mint(basketsHeld.bottom - needed);

215:             needed = rToken.basketsNeeded().mul(FIX_ONE + backingBuffer); // keep buffer

215:             needed = rToken.basketsNeeded().mul(FIX_ONE + backingBuffer); // keep buffer

215:             needed = rToken.basketsNeeded().mul(FIX_ONE + backingBuffer); // keep buffer

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

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

236:                 uint256 tokensPerShare = delta / (totals.rTokenTotal + totals.rsrTotal);

236:                 uint256 tokensPerShare = delta / (totals.rTokenTotal + totals.rsrTotal);

242:                     erc20s[i].safeTransfer(address(rsrTrader), tokensPerShare * totals.rsrTotal);

247:                         tokensPerShare * totals.rTokenTotal
File: contracts/p1/BasketHandler.sol

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";

7: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

7: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

7: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

7: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

8: import "../interfaces/IAssetRegistry.sol";

8: import "../interfaces/IAssetRegistry.sol";

9: import "../interfaces/IBasketHandler.sol";

9: import "../interfaces/IBasketHandler.sol";

10: import "../interfaces/IMain.sol";

10: import "../interfaces/IMain.sol";

11: import "../libraries/Array.sol";

11: import "../libraries/Array.sol";

12: import "../libraries/Fixed.sol";

12: import "../libraries/Fixed.sol";

13: import "./mixins/BasketLib.sol";

13: import "./mixins/BasketLib.sol";

14: import "./mixins/Component.sol";

14: import "./mixins/Component.sol";

27:     uint192 public constant MAX_TARGET_AMT = 1e3 * FIX_ONE; // {target/BU} max basket weight

27:     uint192 public constant MAX_TARGET_AMT = 1e3 * FIX_ONE; // {target/BU} max basket weight

27:     uint192 public constant MAX_TARGET_AMT = 1e3 * FIX_ONE; // {target/BU} max basket weight

27:     uint192 public constant MAX_TARGET_AMT = 1e3 * FIX_ONE; // {target/BU} max basket weight

28:     uint48 public constant MIN_WARMUP_PERIOD = 60; // {s} 1 minute

28:     uint48 public constant MIN_WARMUP_PERIOD = 60; // {s} 1 minute

29:     uint48 public constant MAX_WARMUP_PERIOD = 31536000; // {s} 1 year

29:     uint48 public constant MAX_WARMUP_PERIOD = 31536000; // {s} 1 year

46:     uint48 public nonce; // {basketNonce} A unique identifier for this basket instance

46:     uint48 public nonce; // {basketNonce} A unique identifier for this basket instance

47:     uint48 public timestamp; // The timestamp when this basket was last set

47:     uint48 public timestamp; // The timestamp when this basket was last set

64:     uint48 public warmupPeriod; // {s} how long to wait until issuance/trading after regaining SOUND

64:     uint48 public warmupPeriod; // {s} how long to wait until issuance/trading after regaining SOUND

64:     uint48 public warmupPeriod; // {s} how long to wait until issuance/trading after regaining SOUND

78:     EnumerableMap.Bytes32ToUintMap private _targetAmts; // targetName -> {target/BU}

78:     EnumerableMap.Bytes32ToUintMap private _targetAmts; // targetName -> {target/BU}

78:     EnumerableMap.Bytes32ToUintMap private _targetAmts; // targetName -> {target/BU}

78:     EnumerableMap.Bytes32ToUintMap private _targetAmts; // targetName -> {target/BU}

119:         for (uint256 i = 0; i < len; ++i) refAmts[i] = basket.refAmts[basket.erc20s[i]];

119:         for (uint256 i = 0; i < len; ++i) refAmts[i] = basket.refAmts[basket.erc20s[i]];

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

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

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

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

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

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

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

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

264:             (block.timestamp >= lastStatusTimestamp + warmupPeriod);

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

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

339:             low256 += qty.safeMul(lowP, RoundingMode.FLOOR);

340:             high256 += qty.safeMul(highP, RoundingMode.CEIL);

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

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

394:         uint256 len; // length of return arrays

394:         uint256 len; // length of return arrays

397:         for (uint48 i = 0; i < basketNonces.length; ++i) {

397:         for (uint48 i = 0; i < basketNonces.length; ++i) {

402:             for (uint256 j = 0; j < b.erc20s.length; ++j) {

402:             for (uint256 j = 0; j < b.erc20s.length; ++j) {

408:                 for (uint256 k = 0; k < len; ++k) {

408:                 for (uint256 k = 0; k < len; ++k) {

422:                     ++len;

422:                     ++len;

425:                     refAmtsAll[erc20Index] += amt;

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

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

438:                 if (!asset.isCollateral()) continue; // skip token if no longer registered

438:                 if (!asset.isCollateral()) continue; // skip token if no longer registered

452:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

452:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

452:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

452:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

452:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

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

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

513:             nonce += 1;

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

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

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

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

548:                 contains ? amt + config.targetAmts[erc20] : config.targetAmts[erc20]

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

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

558:             if (amt > newTargetAmts[i]) _targetAmts.set(targetName, amt - newTargetAmts[i]);

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

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

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

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

598:                 if (!asset.isCollateral()) continue; // skip token if no longer registered

598:                 if (!asset.isCollateral()) continue; // skip token if no longer registered

610:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

610:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

610:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

610:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

610:                 if (errData.length == 0) revert(); // solhint-disable-line reason-string

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

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

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

651:         for (uint256 i = 0; i < erc20s.length; ++i) {
File: contracts/p1/Broker.sol

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

6: import "@openzeppelin/contracts/proxy/Clones.sol";

6: import "@openzeppelin/contracts/proxy/Clones.sol";

6: import "@openzeppelin/contracts/proxy/Clones.sol";

7: import "../interfaces/IBroker.sol";

7: import "../interfaces/IBroker.sol";

8: import "../interfaces/IMain.sol";

8: import "../interfaces/IMain.sol";

9: import "../interfaces/ITrade.sol";

9: import "../interfaces/ITrade.sol";

10: import "../libraries/Fixed.sol";

10: import "../libraries/Fixed.sol";

11: import "./mixins/Component.sol";

11: import "./mixins/Component.sol";

12: import "../plugins/trading/DutchTrade.sol";

12: import "../plugins/trading/DutchTrade.sol";

12: import "../plugins/trading/DutchTrade.sol";

13: import "../plugins/trading/GnosisTrade.sol";

13: import "../plugins/trading/GnosisTrade.sol";

13: import "../plugins/trading/GnosisTrade.sol";

25:     uint48 public constant MAX_AUCTION_LENGTH = 604800; // {s} max valid duration - 1 week

25:     uint48 public constant MAX_AUCTION_LENGTH = 604800; // {s} max valid duration - 1 week

25:     uint48 public constant MAX_AUCTION_LENGTH = 604800; // {s} max valid duration - 1 week

26:     uint48 public constant MIN_AUCTION_LENGTH = ONE_BLOCK * 2; // {s} min auction length - 2 blocks

26:     uint48 public constant MIN_AUCTION_LENGTH = ONE_BLOCK * 2; // {s} min auction length - 2 blocks

26:     uint48 public constant MIN_AUCTION_LENGTH = ONE_BLOCK * 2; // {s} min auction length - 2 blocks

26:     uint48 public constant MIN_AUCTION_LENGTH = ONE_BLOCK * 2; // {s} min auction length - 2 blocks
File: contracts/p1/Deployer.sol

4: import "@openzeppelin/contracts/proxy/Clones.sol";

4: import "@openzeppelin/contracts/proxy/Clones.sol";

4: import "@openzeppelin/contracts/proxy/Clones.sol";

5: import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

5: import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

5: import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

5: import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

6: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

6: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

6: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

6: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

6: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

7: import "../interfaces/IAsset.sol";

7: import "../interfaces/IAsset.sol";

8: import "../interfaces/IAssetRegistry.sol";

8: import "../interfaces/IAssetRegistry.sol";

9: import "../interfaces/IBackingManager.sol";

9: import "../interfaces/IBackingManager.sol";

10: import "../interfaces/IBasketHandler.sol";

10: import "../interfaces/IBasketHandler.sol";

11: import "../interfaces/IBroker.sol";

11: import "../interfaces/IBroker.sol";

12: import "../interfaces/IDeployer.sol";

12: import "../interfaces/IDeployer.sol";

13: import "../interfaces/IDistributor.sol";

13: import "../interfaces/IDistributor.sol";

14: import "../interfaces/IFurnace.sol";

14: import "../interfaces/IFurnace.sol";

15: import "../interfaces/IRevenueTrader.sol";

15: import "../interfaces/IRevenueTrader.sol";

16: import "../interfaces/IRToken.sol";

16: import "../interfaces/IRToken.sol";

17: import "../interfaces/IStRSR.sol";

17: import "../interfaces/IStRSR.sol";

18: import "../mixins/Versioned.sol";

18: import "../mixins/Versioned.sol";

19: import "../plugins/assets/Asset.sol";

19: import "../plugins/assets/Asset.sol";

19: import "../plugins/assets/Asset.sol";

20: import "../plugins/assets/RTokenAsset.sol";

20: import "../plugins/assets/RTokenAsset.sol";

20: import "../plugins/assets/RTokenAsset.sol";

21: import "./Main.sol";

22: import "../libraries/String.sol";

22: import "../libraries/String.sol";
File: contracts/p1/Distributor.sol

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

6: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

7: import "../interfaces/IDistributor.sol";

7: import "../interfaces/IDistributor.sol";

8: import "../interfaces/IMain.sol";

8: import "../interfaces/IMain.sol";

9: import "../libraries/Fixed.sol";

9: import "../libraries/Fixed.sol";

10: import "./mixins/Component.sol";

10: import "./mixins/Component.sol";

34:     uint8 public constant MAX_DESTINATIONS_ALLOWED = MAX_DESTINATIONS; // 100

34:     uint8 public constant MAX_DESTINATIONS_ALLOWED = MAX_DESTINATIONS; // 100

89:         bool isRSR = erc20 == rsr; // if false: isRToken

89:         bool isRSR = erc20 == rsr; // if false: isRToken

95:             tokensPerShare = amount / totalShares;

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

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

111:             uint256 transferAmt = tokensPerShare * numberOfShares;

124:             numTransfers++;

124:             numTransfers++;

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

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

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

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

141:             revTotals.rTokenTotal += share.rTokenDist;

142:             revTotals.rsrTotal += share.rsrDist;
File: contracts/p1/Furnace.sol

4: import "../libraries/Fixed.sol";

4: import "../libraries/Fixed.sol";

5: import "../interfaces/IFurnace.sol";

5: import "../interfaces/IFurnace.sol";

6: import "./mixins/Component.sol";

6: import "./mixins/Component.sol";

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

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

16:     uint48 public constant PERIOD = ONE_BLOCK; // {s} 12 seconds; 1 block on PoS Ethereum

16:     uint48 public constant PERIOD = ONE_BLOCK; // {s} 12 seconds; 1 block on PoS Ethereum

21:     uint192 public ratio; // {1} What fraction of balance to melt each period

21:     uint192 public ratio; // {1} What fraction of balance to melt each period

24:     uint48 public lastPayout; // {seconds} The last time we did a payout

24:     uint48 public lastPayout; // {seconds} The last time we did a payout

25:     uint256 public lastPayoutBal; // {qRTok} The balance of RToken at the last payout

25:     uint256 public lastPayoutBal; // {qRTok} The balance of RToken at the last payout

67:         if (uint48(block.timestamp) < uint64(lastPayout) + PERIOD) return;

70:         uint48 numPeriods = uint48((block.timestamp) - lastPayout) / PERIOD;

70:         uint48 numPeriods = uint48((block.timestamp) - lastPayout) / PERIOD;

77:         lastPayout += numPeriods * PERIOD;

77:         lastPayout += numPeriods * PERIOD;

78:         lastPayoutBal = rToken.balanceOf(address(this)) - amount;
File: contracts/p1/Main.sol

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

8: import "../interfaces/IMain.sol";

8: import "../interfaces/IMain.sol";

9: import "../mixins/ComponentRegistry.sol";

9: import "../mixins/ComponentRegistry.sol";

10: import "../mixins/Auth.sol";

10: import "../mixins/Auth.sol";

11: import "../mixins/Versioned.sol";

11: import "../mixins/Versioned.sol";
File: contracts/p1/RToken.sol

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "../interfaces/IMain.sol";

6: import "../interfaces/IMain.sol";

7: import "../interfaces/IRToken.sol";

7: import "../interfaces/IRToken.sol";

8: import "../libraries/Fixed.sol";

8: import "../libraries/Fixed.sol";

9: import "../libraries/Throttle.sol";

9: import "../libraries/Throttle.sol";

10: import "../vendor/ERC20PermitUpgradeable.sol";

10: import "../vendor/ERC20PermitUpgradeable.sol";

11: import "./mixins/Component.sol";

11: import "./mixins/Component.sol";

22:     uint256 public constant MIN_THROTTLE_RATE_AMT = 1e18; // {qRTok}

22:     uint256 public constant MIN_THROTTLE_RATE_AMT = 1e18; // {qRTok}

23:     uint256 public constant MAX_THROTTLE_RATE_AMT = 1e48; // {qRTok}

23:     uint256 public constant MAX_THROTTLE_RATE_AMT = 1e48; // {qRTok}

24:     uint192 public constant MAX_THROTTLE_PCT_AMT = 1e18; // {qRTok}

24:     uint192 public constant MAX_THROTTLE_PCT_AMT = 1e18; // {qRTok}

25:     uint192 public constant MIN_EXCHANGE_RATE = 1e9; // D18{BU/rTok}

25:     uint192 public constant MIN_EXCHANGE_RATE = 1e9; // D18{BU/rTok}

25:     uint192 public constant MIN_EXCHANGE_RATE = 1e9; // D18{BU/rTok}

26:     uint192 public constant MAX_EXCHANGE_RATE = 1e27; // D18{BU/rTok}

26:     uint192 public constant MAX_EXCHANGE_RATE = 1e27; // D18{BU/rTok}

26:     uint192 public constant MAX_EXCHANGE_RATE = 1e27; // D18{BU/rTok}

55:     uint192 public basketsNeeded; // D18{BU}

55:     uint192 public basketsNeeded; // D18{BU}

110:         address issuer = _msgSender(); // OK to save: it can't be changed in reentrant runs

110:         address issuer = _msgSender(); // OK to save: it can't be changed in reentrant runs

119:         issuanceThrottle.useAvailable(supply, int256(amount)); // reverts on over-issuance

119:         issuanceThrottle.useAvailable(supply, int256(amount)); // reverts on over-issuance

119:         issuanceThrottle.useAvailable(supply, int256(amount)); // reverts on over-issuance

120:         redemptionThrottle.useAvailable(supply, -int256(amount)); // shouldn't revert

120:         redemptionThrottle.useAvailable(supply, -int256(amount)); // shouldn't revert

120:         redemptionThrottle.useAvailable(supply, -int256(amount)); // shouldn't revert

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

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

184:         try main.furnace().melt() {} catch {} // nice for the redeemer, but not necessary

184:         try main.furnace().melt() {} catch {} // nice for the redeemer, but not necessary

196:         issuanceThrottle.useAvailable(supply, -int256(amount));

197:         redemptionThrottle.useAvailable(supply, int256(amount)); // reverts on over-redemption

197:         redemptionThrottle.useAvailable(supply, int256(amount)); // reverts on over-redemption

197:         redemptionThrottle.useAvailable(supply, int256(amount)); // reverts on over-redemption

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

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

264:         for (uint256 i = 0; i < portions.length; ++i) {

264:         for (uint256 i = 0; i < portions.length; ++i) {

265:             portionsSum += portions[i];

272:         issuanceThrottle.useAvailable(supply, -int256(amount));

273:         redemptionThrottle.useAvailable(supply, int256(amount)); // reverts on over-redemption

273:         redemptionThrottle.useAvailable(supply, int256(amount)); // reverts on over-redemption

273:         redemptionThrottle.useAvailable(supply, int256(amount)); // reverts on over-redemption

292:         for (uint256 i = 0; i < erc20sOut.length; ++i) {

292:         for (uint256 i = 0; i < erc20sOut.length; ++i) {

298:             ); // FLOOR

298:             ); // FLOOR

306:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {

306:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {

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

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

317:                 if (amountsOut[i] == 0) continue; // unregistered ERC20s will have 0 amount

317:                 if (amountsOut[i] == 0) continue; // unregistered ERC20s will have 0 amount

333:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {

333:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {

336:             require(bal - pastBals[i] >= minAmounts[i], "redemption below minimum");

401:         uint256 low = (FIX_ONE_256 * basketsNeeded) / supply; // D18{BU/rTok}

401:         uint256 low = (FIX_ONE_256 * basketsNeeded) / supply; // D18{BU/rTok}

401:         uint256 low = (FIX_ONE_256 * basketsNeeded) / supply; // D18{BU/rTok}

401:         uint256 low = (FIX_ONE_256 * basketsNeeded) / supply; // D18{BU/rTok}

401:         uint256 low = (FIX_ONE_256 * basketsNeeded) / supply; // D18{BU/rTok}

402:         uint256 high = (FIX_ONE_256 * basketsNeeded + (supply - 1)) / supply; // D18{BU/rTok}

402:         uint256 high = (FIX_ONE_256 * basketsNeeded + (supply - 1)) / supply; // D18{BU/rTok}

402:         uint256 high = (FIX_ONE_256 * basketsNeeded + (supply - 1)) / supply; // D18{BU/rTok}

402:         uint256 high = (FIX_ONE_256 * basketsNeeded + (supply - 1)) / supply; // D18{BU/rTok}

402:         uint256 high = (FIX_ONE_256 * basketsNeeded + (supply - 1)) / supply; // D18{BU/rTok}

402:         uint256 high = (FIX_ONE_256 * basketsNeeded + (supply - 1)) / supply; // D18{BU/rTok}

402:         uint256 high = (FIX_ONE_256 * basketsNeeded + (supply - 1)) / supply; // D18{BU/rTok}

479:             ? amtBaskets.muluDivu(totalSupply, basketsNeeded) // {rTok} = {BU} * {qRTok} * {qRTok}

479:             ? amtBaskets.muluDivu(totalSupply, basketsNeeded) // {rTok} = {BU} * {qRTok} * {qRTok}

479:             ? amtBaskets.muluDivu(totalSupply, basketsNeeded) // {rTok} = {BU} * {qRTok} * {qRTok}

479:             ? amtBaskets.muluDivu(totalSupply, basketsNeeded) // {rTok} = {BU} * {qRTok} * {qRTok}

480:             : amtBaskets; // {rTok}

480:             : amtBaskets; // {rTok}

481:         emit BasketsNeededChanged(basketsNeeded, basketsNeeded + amtBaskets);

482:         basketsNeeded += amtBaskets;

499:         amtBaskets = basketsNeeded.muluDivu(amtRToken, totalSupply()); // FLOOR

499:         amtBaskets = basketsNeeded.muluDivu(amtRToken, totalSupply()); // FLOOR

500:         emit BasketsNeededChanged(basketsNeeded, basketsNeeded - amtBaskets);

501:         basketsNeeded -= amtBaskets;
File: contracts/p1/RevenueTrader.sol

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "../interfaces/IMain.sol";

6: import "../interfaces/IMain.sol";

7: import "../interfaces/IAssetRegistry.sol";

7: import "../interfaces/IAssetRegistry.sol";

8: import "./mixins/Trading.sol";

8: import "./mixins/Trading.sol";

9: import "./mixins/TradeLib.sol";

9: import "./mixins/TradeLib.sol";

49:         trade = super.settleTrade(sell); // nonReentrant

49:         trade = super.settleTrade(sell); // nonReentrant

114:         (uint192 sellPrice, ) = sell.price(); // {UoA/tok}

114:         (uint192 sellPrice, ) = sell.price(); // {UoA/tok}

114:         (uint192 sellPrice, ) = sell.price(); // {UoA/tok}

115:         (, uint192 buyPrice) = buy.price(); // {UoA/tok}

115:         (, uint192 buyPrice) = buy.price(); // {UoA/tok}

115:         (, uint192 buyPrice) = buy.price(); // {UoA/tok}
File: contracts/p1/StRSR.sol

4: import "@openzeppelin/contracts-upgradeable/interfaces/IERC1271Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/interfaces/IERC1271Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/interfaces/IERC1271Upgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/interfaces/IERC1271Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";

7: import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";

7: import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";

7: import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";

7: import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";

7: import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";

7: import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";

8: import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";

8: import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";

8: import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";

8: import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";

9: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

9: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

9: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

9: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

11: import "../interfaces/IStRSR.sol";

11: import "../interfaces/IStRSR.sol";

12: import "../interfaces/IMain.sol";

12: import "../interfaces/IMain.sol";

13: import "../libraries/Fixed.sol";

13: import "../libraries/Fixed.sol";

14: import "../libraries/Permit.sol";

14: import "../libraries/Permit.sol";

15: import "./mixins/Component.sol";

15: import "./mixins/Component.sol";

37:     uint48 public constant PERIOD = ONE_BLOCK; // {s} 12 seconds; 1 block on PoS Ethereum

37:     uint48 public constant PERIOD = ONE_BLOCK; // {s} 12 seconds; 1 block on PoS Ethereum

38:     uint48 public constant MIN_UNSTAKING_DELAY = PERIOD * 2; // {s}

38:     uint48 public constant MIN_UNSTAKING_DELAY = PERIOD * 2; // {s}

38:     uint48 public constant MIN_UNSTAKING_DELAY = PERIOD * 2; // {s}

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

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

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

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

43:     string public name; // immutable

43:     string public name; // immutable

44:     string public symbol; // immutable

44:     string public symbol; // immutable

61:     mapping(uint256 => mapping(address => uint256)) private stakes; // Stakes per account {qStRSR}

61:     mapping(uint256 => mapping(address => uint256)) private stakes; // Stakes per account {qStRSR}

62:     uint256 private totalStakes; // Total of all stakes {qStRSR}

62:     uint256 private totalStakes; // Total of all stakes {qStRSR}

63:     uint256 private stakeRSR; // Amount of RSR backing all stakes {qRSR}

63:     uint256 private stakeRSR; // Amount of RSR backing all stakes {qRSR}

64:     uint192 private stakeRate; // The exchange rate between stakes and RSR. D18{qStRSR/qRSR}

64:     uint192 private stakeRate; // The exchange rate between stakes and RSR. D18{qStRSR/qRSR}

64:     uint192 private stakeRate; // The exchange rate between stakes and RSR. D18{qStRSR/qRSR}

66:     uint192 private constant MAX_STAKE_RATE = 1e9 * FIX_ONE; // 1e9 D18{qStRSR/qRSR}

66:     uint192 private constant MAX_STAKE_RATE = 1e9 * FIX_ONE; // 1e9 D18{qStRSR/qRSR}

66:     uint192 private constant MAX_STAKE_RATE = 1e9 * FIX_ONE; // 1e9 D18{qStRSR/qRSR}

66:     uint192 private constant MAX_STAKE_RATE = 1e9 * FIX_ONE; // 1e9 D18{qStRSR/qRSR}

78:         uint176 drafts; // Total amount of drafts that will become available // {qDrafts}

78:         uint176 drafts; // Total amount of drafts that will become available // {qDrafts}

78:         uint176 drafts; // Total amount of drafts that will become available // {qDrafts}

78:         uint176 drafts; // Total amount of drafts that will become available // {qDrafts}

79:         uint64 availableAt; // When the last of the drafts will become available

79:         uint64 availableAt; // When the last of the drafts will become available

82:     mapping(uint256 => mapping(address => CumulativeDraft[])) public draftQueues; // {drafts}

82:     mapping(uint256 => mapping(address => CumulativeDraft[])) public draftQueues; // {drafts}

83:     mapping(uint256 => mapping(address => uint256)) public firstRemainingDraft; // draft index

83:     mapping(uint256 => mapping(address => uint256)) public firstRemainingDraft; // draft index

84:     uint256 private totalDrafts; // Total of all drafts {qDrafts}

84:     uint256 private totalDrafts; // Total of all drafts {qDrafts}

85:     uint256 private draftRSR; // Amount of RSR backing all drafts {qRSR}

85:     uint256 private draftRSR; // Amount of RSR backing all drafts {qRSR}

86:     uint192 public draftRate; // The exchange rate between drafts and RSR. D18{qDrafts/qRSR}

86:     uint192 public draftRate; // The exchange rate between drafts and RSR. D18{qDrafts/qRSR}

86:     uint192 public draftRate; // The exchange rate between drafts and RSR. D18{qDrafts/qRSR}

88:     uint192 private constant MAX_DRAFT_RATE = 1e9 * FIX_ONE; // 1e9 D18{qDrafts/qRSR}

88:     uint192 private constant MAX_DRAFT_RATE = 1e9 * FIX_ONE; // 1e9 D18{qDrafts/qRSR}

88:     uint192 private constant MAX_DRAFT_RATE = 1e9 * FIX_ONE; // 1e9 D18{qDrafts/qRSR}

88:     uint192 private constant MAX_DRAFT_RATE = 1e9 * FIX_ONE; // 1e9 D18{qDrafts/qRSR}

136:     uint48 public unstakingDelay; // {s} The minimum length of time spent in the draft queue

136:     uint48 public unstakingDelay; // {s} The minimum length of time spent in the draft queue

137:     uint192 public rewardRatio; // {1} The fraction of the revenue balance to handout per period

137:     uint192 public rewardRatio; // {1} The fraction of the revenue balance to handout per period

155:     uint192 private constant MAX_WITHDRAWAL_LEAK = 3e17; // {1} 30%

155:     uint192 private constant MAX_WITHDRAWAL_LEAK = 3e17; // {1} 30%

157:     uint192 private leaked; // {1} stake fraction that has withdrawn without a refresh

157:     uint192 private leaked; // {1} stake fraction that has withdrawn without a refresh

158:     uint48 private lastWithdrawRefresh; // {s} timestamp of last refresh() during withdraw()

158:     uint48 private lastWithdrawRefresh; // {s} timestamp of last refresh() during withdraw()

159:     uint192 public withdrawalLeak; // {1} gov param -- % RSR that can be withdrawn without refresh

159:     uint192 public withdrawalLeak; // {1} gov param -- % RSR that can be withdrawn without refresh

159:     uint192 public withdrawalLeak; // {1} gov param -- % RSR that can be withdrawn without refresh

159:     uint192 public withdrawalLeak; // {1} gov param -- % RSR that can be withdrawn without refresh

268:         uint256 newStakeRSR = (FIX_ONE_256 * totalStakes + (stakeRate - 1)) / stakeRate;

268:         uint256 newStakeRSR = (FIX_ONE_256 * totalStakes + (stakeRate - 1)) / stakeRate;

268:         uint256 newStakeRSR = (FIX_ONE_256 * totalStakes + (stakeRate - 1)) / stakeRate;

268:         uint256 newStakeRSR = (FIX_ONE_256 * totalStakes + (stakeRate - 1)) / stakeRate;

269:         uint256 rsrAmount = stakeRSR - newStakeRSR;

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

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

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

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

312:         uint192 draftAmount = queue[endId - 1].drafts - oldDrafts;

312:         uint192 draftAmount = queue[endId - 1].drafts - oldDrafts;

318:         uint256 newTotalDrafts = totalDrafts - draftAmount;

320:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

320:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

320:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

320:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

321:         uint256 rsrAmount = draftRSR - newDraftRSR;

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

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

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

359:         uint192 draftAmount = queue[endId - 1].drafts - oldDrafts;

359:         uint192 draftAmount = queue[endId - 1].drafts - oldDrafts;

365:         uint256 newTotalDrafts = totalDrafts - draftAmount;

367:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

367:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

367:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

367:         uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;

368:         uint256 rsrAmount = draftRSR - newDraftRSR;

432:         uint256 stakeRSRToTake = (stakeRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

432:         uint256 stakeRSRToTake = (stakeRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

432:         uint256 stakeRSRToTake = (stakeRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

432:         uint256 stakeRSRToTake = (stakeRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

433:         stakeRSR -= stakeRSRToTake;

439:             stakeRate = uint192((FIX_ONE_256 * totalStakes + (stakeRSR - 1)) / stakeRSR);

439:             stakeRate = uint192((FIX_ONE_256 * totalStakes + (stakeRSR - 1)) / stakeRSR);

439:             stakeRate = uint192((FIX_ONE_256 * totalStakes + (stakeRSR - 1)) / stakeRSR);

439:             stakeRate = uint192((FIX_ONE_256 * totalStakes + (stakeRSR - 1)) / stakeRSR);

442:             seizedRSR += stakeRSR;

447:         uint256 draftRSRToTake = (draftRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

447:         uint256 draftRSRToTake = (draftRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

447:         uint256 draftRSRToTake = (draftRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

447:         uint256 draftRSRToTake = (draftRSR * rsrAmount + (rsrBalance - 1)) / rsrBalance;

448:         draftRSR -= draftRSRToTake;

449:         seizedRSR += draftRSRToTake;

454:             draftRate = uint192((FIX_ONE_256 * totalDrafts + (draftRSR - 1)) / draftRSR);

454:             draftRate = uint192((FIX_ONE_256 * totalDrafts + (draftRSR - 1)) / draftRSR);

454:             draftRate = uint192((FIX_ONE_256 * totalDrafts + (draftRSR - 1)) / draftRSR);

454:             draftRate = uint192((FIX_ONE_256 * totalDrafts + (draftRSR - 1)) / draftRSR);

458:             seizedRSR += draftRSR;

463:         seizedRSR += (rewards * rsrAmount + (rsrBalance - 1)) / rsrBalance;

463:         seizedRSR += (rewards * rsrAmount + (rsrBalance - 1)) / rsrBalance;

463:         seizedRSR += (rewards * rsrAmount + (rsrBalance - 1)) / rsrBalance;

463:         seizedRSR += (rewards * rsrAmount + (rsrBalance - 1)) / rsrBalance;

463:         seizedRSR += (rewards * rsrAmount + (rsrBalance - 1)) / rsrBalance;

464:         rsrRewardsAtLastPayout = rsrRewards() - seizedRSR;

474:         return (FIX_SCALE_SQ + (stakeRate / 2)) / stakeRate; // ROUND method

474:         return (FIX_SCALE_SQ + (stakeRate / 2)) / stakeRate; // ROUND method

474:         return (FIX_SCALE_SQ + (stakeRate / 2)) / stakeRate; // ROUND method

474:         return (FIX_SCALE_SQ + (stakeRate / 2)) / stakeRate; // ROUND method

474:         return (FIX_SCALE_SQ + (stakeRate / 2)) / stakeRate; // ROUND method

496:         while (left < right - 1) {

500:             test = (left + right) / 2; // left < test < right because left < right - 1

500:             test = (left + right) / 2; // left < test < right because left < right - 1

500:             test = (left + right) / 2; // left < test < right because left < right - 1

500:             test = (left + right) / 2; // left < test < right because left < right - 1

500:             test = (left + right) / 2; // left < test < right because left < right - 1

559:         if (block.timestamp < payoutLastPaid + PERIOD) return;

560:         uint48 numPeriods = (uint48(block.timestamp) - payoutLastPaid) / PERIOD;

560:         uint48 numPeriods = (uint48(block.timestamp) - payoutLastPaid) / PERIOD;

571:             uint192 payoutRatio = FIX_ONE - FixLib.powu(FIX_ONE - rewardRatio, numPeriods);

571:             uint192 payoutRatio = FIX_ONE - FixLib.powu(FIX_ONE - rewardRatio, numPeriods);

574:             payout = (payoutRatio * rsrRewardsAtLastPayout) / FIX_ONE;

574:             payout = (payoutRatio * rsrRewardsAtLastPayout) / FIX_ONE;

575:             stakeRSR += payout;

578:         payoutLastPaid += numPeriods * PERIOD;

578:         payoutLastPaid += numPeriods * PERIOD;

588:             : uint192((totalStakes * FIX_ONE_256 + (stakeRSR - 1)) / stakeRSR);

588:             : uint192((totalStakes * FIX_ONE_256 + (stakeRSR - 1)) / stakeRSR);

588:             : uint192((totalStakes * FIX_ONE_256 + (stakeRSR - 1)) / stakeRSR);

588:             : uint192((totalStakes * FIX_ONE_256 + (stakeRSR - 1)) / stakeRSR);

611:         draftRSR += rsrAmount;

613:         uint256 newTotalDrafts = (draftRate * draftRSR) / FIX_ONE;

613:         uint256 newTotalDrafts = (draftRate * draftRSR) / FIX_ONE;

614:         uint256 draftAmount = newTotalDrafts - totalDrafts;

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

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

623:         availableAt = uint64(block.timestamp) + unstakingDelay;

628:         queue.push(CumulativeDraft(uint176(oldDrafts + draftAmount), availableAt));

640:         era++;

640:         era++;

652:         draftEra++;

652:         draftEra++;

659:         return rsr.balanceOf(address(this)) - stakeRSR - draftRSR;

659:         return rsr.balanceOf(address(this)) - stakeRSR - draftRSR;

666:         uint48 lastRefresh = assetRegistry.lastRefresh(); // {s}

666:         uint48 lastRefresh = assetRegistry.lastRefresh(); // {s}

669:         uint256 totalRSR = stakeRSR + draftRSR + rsrWithdrawal; // {qRSR}

669:         uint256 totalRSR = stakeRSR + draftRSR + rsrWithdrawal; // {qRSR}

669:         uint256 totalRSR = stakeRSR + draftRSR + rsrWithdrawal; // {qRSR}

669:         uint256 totalRSR = stakeRSR + draftRSR + rsrWithdrawal; // {qRSR}

670:         uint192 withdrawal = _safeWrap((rsrWithdrawal * FIX_ONE + totalRSR - 1) / totalRSR); // {1}

670:         uint192 withdrawal = _safeWrap((rsrWithdrawal * FIX_ONE + totalRSR - 1) / totalRSR); // {1}

670:         uint192 withdrawal = _safeWrap((rsrWithdrawal * FIX_ONE + totalRSR - 1) / totalRSR); // {1}

670:         uint192 withdrawal = _safeWrap((rsrWithdrawal * FIX_ONE + totalRSR - 1) / totalRSR); // {1}

670:         uint192 withdrawal = _safeWrap((rsrWithdrawal * FIX_ONE + totalRSR - 1) / totalRSR); // {1}

670:         uint192 withdrawal = _safeWrap((rsrWithdrawal * FIX_ONE + totalRSR - 1) / totalRSR); // {1}

673:         leaked = lastWithdrawRefresh != lastRefresh ? withdrawal : leaked + withdrawal;

692:         uint256 newStakeRSR = stakeRSR + rsrAmount;

694:         uint256 newTotalStakes = (stakeRate * newStakeRSR) / FIX_ONE;

694:         uint256 newTotalStakes = (stakeRate * newStakeRSR) / FIX_ONE;

695:         uint256 stakeAmount = newTotalStakes - totalStakes;

698:         stakeRSR += rsrAmount;

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

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

797:             eraStakes[from] = fromBalance - amount;

799:         eraStakes[to] += amount;

811:         assert(totalStakes + amount < type(uint224).max);

813:         stakes[era][account] += amount;

814:         totalStakes += amount;

834:             eraStakes[account] = accountBalance - amount;

836:         totalStakes -= amount;

863:                 _approve(owner, spender, currentAllowance - amount);
File: contracts/p1/StRSRVotes.sol

4: import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";

6: import "../interfaces/IStRSRVotes.sol";

6: import "../interfaces/IStRSRVotes.sol";

7: import "./StRSR.sol";

34:     Checkpoint[] private _eras; // {era}

34:     Checkpoint[] private _eras; // {era}

38:     mapping(uint256 => mapping(address => Checkpoint[])) private _checkpoints; // {qStRSR}

38:     mapping(uint256 => mapping(address => Checkpoint[])) private _checkpoints; // {qStRSR}

40:     mapping(uint256 => Checkpoint[]) private _totalSupplyCheckpoints; // {qStRSR}

40:     mapping(uint256 => Checkpoint[]) private _totalSupplyCheckpoints; // {qStRSR}

73:         return pos == 0 ? 0 : _checkpoints[era][account][pos - 1].val;

108:                 low = mid + 1;

111:         return high == 0 ? 0 : ckpts[high - 1].val;

215:         oldWeight = pos == 0 ? 0 : ckpts[pos - 1].val;

218:         if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {

219:             ckpts[pos - 1].val = SafeCastUpgradeable.toUint224(newWeight);

231:         return a + b;

235:         return a - b;
File: contracts/p1/mixins/BasketLib.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

5: import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

7: import "../../interfaces/IAssetRegistry.sol";

7: import "../../interfaces/IAssetRegistry.sol";

7: import "../../interfaces/IAssetRegistry.sol";

8: import "../../libraries/Fixed.sol";

8: import "../../libraries/Fixed.sol";

8: import "../../libraries/Fixed.sol";

14:     uint256 max; // Maximum number of backup collateral erc20s to use in a basket

14:     uint256 max; // Maximum number of backup collateral erc20s to use in a basket

15:     IERC20[] erc20s; // Ordered list of backup collateral ERC20s

15:     IERC20[] erc20s; // Ordered list of backup collateral ERC20s

48:     IERC20[] erc20s; // enumerated keys for refAmts

48:     IERC20[] erc20s; // enumerated keys for refAmts

49:     mapping(IERC20 => uint192) refAmts; // {ref/BU}

49:     mapping(IERC20 => uint192) refAmts; // {ref/BU}

49:     mapping(IERC20 => uint192) refAmts; // {ref/BU}

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

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

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

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

108:        - the basket configuration (config: BasketConfig)

109:        - the function (isGood: erc20 -> bool), implemented here by goodCollateral()

109:        - the function (isGood: erc20 -> bool), implemented here by goodCollateral()

110:        - the function (targetPerRef: erc20 -> Fix) implemented by the Collateral plugin

110:        - the function (targetPerRef: erc20 -> Fix) implemented by the Collateral plugin

117:        Let targetWeight(b, e) = b.refAmt[e] * targetPerRef(e)

128:                          then unsoundPrimeWt(tgt) / len(Backups(tgt))

137:        Else, return true and targetWeight(basket', e) == primeWt(e) + backupWt(e) for all e.

139:        ==== Higher-level desideratum ====

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

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

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

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

196:             for (targetIndex = 0; targetIndex < targetsLength; ++targetIndex) {

196:             for (targetIndex = 0; targetIndex < targetsLength; ++targetIndex) {

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

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

239:             if (totalWeights[i].lte(goodWeights[i])) continue; // Don't need any backup weight

239:             if (totalWeights[i].lte(goodWeights[i])) continue; // Don't need any backup weight

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

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

248:             for (uint256 j = 0; j < backup.erc20s.length && size < backup.max; ++j) {

248:             for (uint256 j = 0; j < backup.erc20s.length && size < backup.max; ++j) {

249:                 if (goodCollateral(targetNames.at(i), backup.erc20s[j], assetRegistry)) size++;

249:                 if (goodCollateral(targetNames.at(i), backup.erc20s[j], assetRegistry)) size++;

259:             for (uint256 j = 0; j < backup.erc20s.length && assigned < size; ++j) {

259:             for (uint256 j = 0; j < backup.erc20s.length && assigned < size; ++j) {

271:                     assigned++;

271:                     assigned++;
File: contracts/p1/mixins/Component.sol

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

4: import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";

7: import "../../interfaces/IComponent.sol";

7: import "../../interfaces/IComponent.sol";

7: import "../../interfaces/IComponent.sol";

8: import "../../interfaces/IMain.sol";

8: import "../../interfaces/IMain.sol";

8: import "../../interfaces/IMain.sol";

9: import "../../mixins/Versioned.sol";

9: import "../../mixins/Versioned.sol";

9: import "../../mixins/Versioned.sol";
File: contracts/p1/mixins/RecollateralizationLib.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "../../interfaces/IAsset.sol";

5: import "../../interfaces/IAsset.sol";

5: import "../../interfaces/IAsset.sol";

6: import "../../interfaces/IAssetRegistry.sol";

6: import "../../interfaces/IAssetRegistry.sol";

6: import "../../interfaces/IAssetRegistry.sol";

7: import "../../interfaces/IBackingManager.sol";

7: import "../../interfaces/IBackingManager.sol";

7: import "../../interfaces/IBackingManager.sol";

8: import "../../libraries/Fixed.sol";

8: import "../../libraries/Fixed.sol";

8: import "../../libraries/Fixed.sol";

9: import "./TradeLib.sol";

16:     BasketRange basketsHeld; // {BU}

16:     BasketRange basketsHeld; // {BU}

28:     uint192 minTradeVolume; // {UoA}

28:     uint192 minTradeVolume; // {UoA}

29:     uint192 maxTradeSlippage; // {1}

29:     uint192 maxTradeSlippage; // {1}

31:     uint192[] quantities; // {tok/BU} basket quantities

31:     uint192[] quantities; // {tok/BU} basket quantities

31:     uint192[] quantities; // {tok/BU} basket quantities

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

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

156:         (uint192 buPriceLow, uint192 buPriceHigh) = ctx.bh.price(); // {UoA/BU}

156:         (uint192 buPriceLow, uint192 buPriceHigh) = ctx.bh.price(); // {UoA/BU}

156:         (uint192 buPriceLow, uint192 buPriceHigh) = ctx.bh.price(); // {UoA/BU}

157:         uint192 basketsNeeded = ctx.rToken.basketsNeeded(); // {BU}

157:         uint192 basketsNeeded = ctx.rToken.basketsNeeded(); // {BU}

170:         int256 deltaTop; // D18{BU} even though this is int256, it is D18

170:         int256 deltaTop; // D18{BU} even though this is int256, it is D18

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

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

178:             uint192 bal = reg.assets[i].bal(address(ctx.bm)); // {tok}

178:             uint192 bal = reg.assets[i].bal(address(ctx.bm)); // {tok}

187:                 (uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/tok}

187:                 (uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/tok}

187:                 (uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/tok}

195:             (uint192 low, uint192 high) = reg.assets[i].price(); // {UoA/tok}

195:             (uint192 low, uint192 high) = reg.assets[i].price(); // {UoA/tok}

195:             (uint192 low, uint192 high) = reg.assets[i].price(); // {UoA/tok}

210:                     deltaTop -= int256(uint256(low.mulDiv(anchor - bal, buPriceHigh, FLOOR)));

210:                     deltaTop -= int256(uint256(low.mulDiv(anchor - bal, buPriceHigh, FLOOR)));

216:                     deltaTop += int256(

217:                         uint256(ctx.bm.safeMulDivCeil(high, bal - anchor, buPriceLow))

231:                 uint192 val = low.mul(bal - anchor, FLOOR);

240:                 val = (val < ctx.minTradeVolume) ? 0 : val - ctx.minTradeVolume;

245:                 range.bottom += val.mulDiv(FIX_ONE.minus(ctx.maxTradeSlippage), buPriceHigh, FLOOR);

253:             range.top = ctx.basketsHeld.top - _safeWrap(uint256(-deltaTop));

253:             range.top = ctx.basketsHeld.top - _safeWrap(uint256(-deltaTop));

257:             if (uint256(deltaTop) + ctx.basketsHeld.top > FIX_MAX) range.top = FIX_MAX;

258:             else range.top = ctx.basketsHeld.top + _safeWrap(uint256(deltaTop));

262:         range.bottom += ctx.basketsHeld.bottom;

277:         CollateralStatus surplusStatus; // starts SOUND

277:         CollateralStatus surplusStatus; // starts SOUND

278:         uint192 surplus; // {UoA}

278:         uint192 surplus; // {UoA}

279:         uint192 deficit; // {UoA}

279:         uint192 deficit; // {UoA}

317:         maxes.surplusStatus = CollateralStatus.IFFY; // least-desirable sell status

317:         maxes.surplusStatus = CollateralStatus.IFFY; // least-desirable sell status

317:         maxes.surplusStatus = CollateralStatus.IFFY; // least-desirable sell status

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

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

324:             uint192 bal = reg.assets[i].bal(address(ctx.bm)); // {tok}

324:             uint192 bal = reg.assets[i].bal(address(ctx.bm)); // {tok}

328:             uint192 needed = range.top.mul(ctx.quantities[i], CEIL); // {tok}

328:             uint192 needed = range.top.mul(ctx.quantities[i], CEIL); // {tok}

331:                 uint192 low; // {UoA/sellTok}

331:                 uint192 low; // {UoA/sellTok}

331:                 uint192 low; // {UoA/sellTok}

335:                     uint192 high; // {UoA/sellTok}

335:                     uint192 high; // {UoA/sellTok}

335:                     uint192 high; // {UoA/sellTok}

336:                     (low, high) = reg.assets[i].price(); // {UoA/sellTok}

336:                     (low, high) = reg.assets[i].price(); // {UoA/sellTok}

336:                     (low, high) = reg.assets[i].price(); // {UoA/sellTok}

342:                 (uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/sellTok}

342:                 (uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/sellTok}

342:                 (uint192 lotLow, ) = reg.assets[i].lotPrice(); // {UoA/sellTok}

348:                 CollateralStatus status; // starts SOUND

348:                 CollateralStatus status; // starts SOUND

373:                 needed = range.bottom.mul(ctx.quantities[i], CEIL); // {buyTok};

373:                 needed = range.bottom.mul(ctx.quantities[i], CEIL); // {buyTok};

376:                     uint192 amtShort = needed.minus(bal); // {buyTok}

376:                     uint192 amtShort = needed.minus(bal); // {buyTok}

377:                     (, uint192 high) = reg.assets[i].price(); // {UoA/buyTok}

377:                     (, uint192 high) = reg.assets[i].price(); // {UoA/buyTok}

377:                     (, uint192 high) = reg.assets[i].price(); // {UoA/buyTok}

401:             (uint192 low, uint192 high) = rsrAsset.price(); // {UoA/tok}

401:             (uint192 low, uint192 high) = rsrAsset.price(); // {UoA/tok}

401:             (uint192 low, uint192 high) = rsrAsset.price(); // {UoA/tok}

402:             (uint192 lotLow, ) = rsrAsset.lotPrice(); // {UoA/tok}

402:             (uint192 lotLow, ) = rsrAsset.lotPrice(); // {UoA/tok}

402:             (uint192 lotLow, ) = rsrAsset.lotPrice(); // {UoA/tok}
File: contracts/p1/mixins/RewardableLib.sol

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/utils/Address.sol";

6: import "@openzeppelin/contracts/utils/Address.sol";

6: import "@openzeppelin/contracts/utils/Address.sol";

7: import "../../interfaces/IAssetRegistry.sol";

7: import "../../interfaces/IAssetRegistry.sol";

7: import "../../interfaces/IAssetRegistry.sol";

8: import "../../interfaces/IBackingManager.sol";

8: import "../../interfaces/IBackingManager.sol";

8: import "../../interfaces/IBackingManager.sol";

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

27:         for (uint256 i = 0; i < registry.erc20s.length; ++i) {
File: contracts/p1/mixins/TradeLib.sol

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

4: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

5: import "../../interfaces/IAsset.sol";

5: import "../../interfaces/IAsset.sol";

5: import "../../interfaces/IAsset.sol";

6: import "../../interfaces/IAssetRegistry.sol";

6: import "../../interfaces/IAssetRegistry.sol";

6: import "../../interfaces/IAssetRegistry.sol";

7: import "../../interfaces/ITrading.sol";

7: import "../../interfaces/ITrading.sol";

7: import "../../interfaces/ITrading.sol";

8: import "../../libraries/Fixed.sol";

8: import "../../libraries/Fixed.sol";

8: import "../../libraries/Fixed.sol";

9: import "./RecollateralizationLib.sol";

14:     uint192 sellAmount; // {sellTok}

14:     uint192 sellAmount; // {sellTok}

15:     uint192 buyAmount; // {buyTok}

15:     uint192 buyAmount; // {buyTok}

16:     uint192 sellPrice; // {UoA/sellTok} can be 0

16:     uint192 sellPrice; // {UoA/sellTok} can be 0

16:     uint192 sellPrice; // {UoA/sellTok} can be 0

17:     uint192 buyPrice; // {UoA/buyTok}

17:     uint192 buyPrice; // {UoA/buyTok}

17:     uint192 buyPrice; // {UoA/buyTok}

59:         uint192 maxSell = maxTradeSize(trade.sell, trade.buy, lotHigh); // {sellTok}

59:         uint192 maxSell = maxTradeSize(trade.sell, trade.buy, lotHigh); // {sellTok}

60:         uint192 s = trade.sellAmount > maxSell ? maxSell : trade.sellAmount; // {sellTok}

60:         uint192 s = trade.sellAmount > maxSell ? maxSell : trade.sellAmount; // {sellTok}

67:             trade.sellPrice, // {UoA/sellTok}

67:             trade.sellPrice, // {UoA/sellTok}

67:             trade.sellPrice, // {UoA/sellTok}

68:             trade.buyPrice // {UoA/buyTok}

68:             trade.buyPrice // {UoA/buyTok}

68:             trade.buyPrice // {UoA/buyTok}

130:         trade.sellAmount = fixMin(slippedSellAmount, trade.sellAmount); // {sellTok}

130:         trade.sellAmount = fixMin(slippedSellAmount, trade.sellAmount); // {sellTok}
File: contracts/p1/mixins/Trading.sol

4: import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

4: import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

5: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

7: import "@openzeppelin/contracts/utils/Multicall.sol";

7: import "@openzeppelin/contracts/utils/Multicall.sol";

7: import "@openzeppelin/contracts/utils/Multicall.sol";

8: import "../../interfaces/ITrade.sol";

8: import "../../interfaces/ITrade.sol";

8: import "../../interfaces/ITrade.sol";

9: import "../../interfaces/ITrading.sol";

9: import "../../interfaces/ITrading.sol";

9: import "../../interfaces/ITrading.sol";

10: import "../../libraries/Fixed.sol";

10: import "../../libraries/Fixed.sol";

10: import "../../libraries/Fixed.sol";

11: import "./Component.sol";

12: import "./RewardableLib.sol";

23:     uint192 public constant MAX_TRADE_VOLUME = 1e29; // {UoA}

23:     uint192 public constant MAX_TRADE_VOLUME = 1e29; // {UoA}

24:     uint192 public constant MAX_TRADE_SLIPPAGE = 1e18; // {%}

24:     uint192 public constant MAX_TRADE_SLIPPAGE = 1e18; // {%}

34:     uint192 public maxTradeSlippage; // {%}

34:     uint192 public maxTradeSlippage; // {%}

36:     uint192 public minTradeVolume; // {UoA}

36:     uint192 public minTradeVolume; // {UoA}

93:         tradesOpen--;

93:         tradesOpen--;

123:         tradesOpen++;

123:         tradesOpen++;
File: contracts/plugins/governance/Governance.sol

4: import "@openzeppelin/contracts/governance/Governor.sol";

4: import "@openzeppelin/contracts/governance/Governor.sol";

4: import "@openzeppelin/contracts/governance/Governor.sol";

5: import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";

5: import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";

5: import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";

5: import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";

6: import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";

6: import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";

6: import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";

6: import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";

7: import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

7: import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

7: import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

7: import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

8: import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";

8: import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";

8: import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";

8: import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";

9: import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";

9: import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";

9: import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";

9: import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";

10: import "../../interfaces/IStRSRVotes.sol";

10: import "../../interfaces/IStRSRVotes.sol";

10: import "../../interfaces/IStRSRVotes.sol";

31:     uint256 public constant ONE_HUNDRED_PERCENT = 1e8; // {micro %}

31:     uint256 public constant ONE_HUNDRED_PERCENT = 1e8; // {micro %}

37:         uint256 votingDelay_, // in blocks

37:         uint256 votingDelay_, // in blocks

38:         uint256 votingPeriod_, // in blocks

38:         uint256 votingPeriod_, // in blocks

39:         uint256 proposalThresholdAsMicroPercent_, // e.g. 1e4 for 0.01%

39:         uint256 proposalThresholdAsMicroPercent_, // e.g. 1e4 for 0.01%

40:         uint256 quorumPercent // e.g 4 for 4%

40:         uint256 quorumPercent // e.g 4 for 4%

66:         uint256 asMicroPercent = super.proposalThreshold(); // {micro %}

66:         uint256 asMicroPercent = super.proposalThreshold(); // {micro %}

67:         uint256 pastSupply = token.getPastTotalSupply(block.number - 1); // {qStRSR}

67:         uint256 pastSupply = token.getPastTotalSupply(block.number - 1); // {qStRSR}

67:         uint256 pastSupply = token.getPastTotalSupply(block.number - 1); // {qStRSR}

71:         return (asMicroPercent * pastSupply + (ONE_HUNDRED_PERCENT - 1)) / ONE_HUNDRED_PERCENT;

71:         return (asMicroPercent * pastSupply + (ONE_HUNDRED_PERCENT - 1)) / ONE_HUNDRED_PERCENT;

71:         return (asMicroPercent * pastSupply + (ONE_HUNDRED_PERCENT - 1)) / ONE_HUNDRED_PERCENT;

71:         return (asMicroPercent * pastSupply + (ONE_HUNDRED_PERCENT - 1)) / ONE_HUNDRED_PERCENT;

156:         bytes memory /*params*/

156:         bytes memory /*params*/

156:         bytes memory /*params*/

156:         bytes memory /*params*/

158:         return token.getPastVotes(account, blockNumber); // {qStRSR}

158:         return token.getPastVotes(account, blockNumber); // {qStRSR}
File: contracts/plugins/trading/DutchTrade.sol

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

5: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

6: import "../../libraries/Fixed.sol";

6: import "../../libraries/Fixed.sol";

6: import "../../libraries/Fixed.sol";

7: import "../../interfaces/IAsset.sol";

7: import "../../interfaces/IAsset.sol";

7: import "../../interfaces/IAsset.sol";

8: import "../../interfaces/ITrade.sol";

8: import "../../interfaces/ITrade.sol";

8: import "../../interfaces/ITrade.sol";

10: uint192 constant FORTY_PERCENT = 4e17; // {1} 0.4

10: uint192 constant FORTY_PERCENT = 4e17; // {1} 0.4

11: uint192 constant SIXTY_PERCENT = 6e17; // {1} 0.6

11: uint192 constant SIXTY_PERCENT = 6e17; // {1} 0.6

19: uint192 constant MAX_EXP = 6907752 * FIX_ONE; // {1} (1000000/999999)^6907752 = ~1000x

19: uint192 constant MAX_EXP = 6907752 * FIX_ONE; // {1} (1000000/999999)^6907752 = ~1000x

19: uint192 constant MAX_EXP = 6907752 * FIX_ONE; // {1} (1000000/999999)^6907752 = ~1000x

19: uint192 constant MAX_EXP = 6907752 * FIX_ONE; // {1} (1000000/999999)^6907752 = ~1000x

20: uint192 constant BASE = 999999e12; // {1} (999999/1000000)

20: uint192 constant BASE = 999999e12; // {1} (999999/1000000)

20: uint192 constant BASE = 999999e12; // {1} (999999/1000000)

47:     TradeStatus public status; // reentrancy protection

47:     TradeStatus public status; // reentrancy protection

49:     ITrading public origin; // the address that initialized the contract

49:     ITrading public origin; // the address that initialized the contract

54:     uint192 public sellAmount; // {sellTok}

54:     uint192 public sellAmount; // {sellTok}

57:     uint48 public startTime; // {s} when the dutch auction begins (12s after init())

57:     uint48 public startTime; // {s} when the dutch auction begins (12s after init())

58:     uint48 public endTime; // {s} when the dutch auction ends if no bids are received

58:     uint48 public endTime; // {s} when the dutch auction ends if no bids are received

61:     uint192 public middlePrice; // {buyTok/sellTok} The price at which the function is piecewise

61:     uint192 public middlePrice; // {buyTok/sellTok} The price at which the function is piecewise

61:     uint192 public middlePrice; // {buyTok/sellTok} The price at which the function is piecewise

62:     uint192 public lowPrice; // {buyTok/sellTok} The price the auction ends at

62:     uint192 public lowPrice; // {buyTok/sellTok} The price the auction ends at

62:     uint192 public lowPrice; // {buyTok/sellTok} The price the auction ends at

110:                 auctionLength >= 2 * ONE_BLOCK

111:         ); // misuse by caller

111:         ); // misuse by caller

114:         (uint192 sellLow, uint192 sellHigh) = sell_.price(); // {UoA/sellTok}

114:         (uint192 sellLow, uint192 sellHigh) = sell_.price(); // {UoA/sellTok}

114:         (uint192 sellLow, uint192 sellHigh) = sell_.price(); // {UoA/sellTok}

115:         (uint192 buyLow, uint192 buyHigh) = buy_.price(); // {UoA/buyTok}

115:         (uint192 buyLow, uint192 buyHigh) = buy_.price(); // {UoA/buyTok}

115:         (uint192 buyLow, uint192 buyHigh) = buy_.price(); // {UoA/buyTok}

124:         sellAmount = shiftl_toFix(sellAmount_, -int8(sell.decimals())); // {sellTok}

124:         sellAmount = shiftl_toFix(sellAmount_, -int8(sell.decimals())); // {sellTok}

124:         sellAmount = shiftl_toFix(sellAmount_, -int8(sell.decimals())); // {sellTok}

125:         startTime = uint48(block.timestamp) + ONE_BLOCK; // start in the next block

125:         startTime = uint48(block.timestamp) + ONE_BLOCK; // start in the next block

125:         startTime = uint48(block.timestamp) + ONE_BLOCK; // start in the next block

126:         endTime = startTime + auctionLength;

130:             sellAmount.mul(sellHigh, FLOOR), // auctionVolume

130:             sellAmount.mul(sellHigh, FLOOR), // auctionVolume

131:             origin.minTradeVolume(), // minTradeVolume

131:             origin.minTradeVolume(), // minTradeVolume

132:             fixMin(sell_.maxTradeVolume(), buy_.maxTradeVolume()) // maxTradeVolume

132:             fixMin(sell_.maxTradeVolume(), buy_.maxTradeVolume()) // maxTradeVolume

136:         lowPrice = sellLow.mulDiv(FIX_ONE - slippage, buyHigh, FLOOR);

137:         middlePrice = sellHigh.div(buyLow, CEIL); // no additional slippage

137:         middlePrice = sellHigh.div(buyLow, CEIL); // no additional slippage

150:         amountIn = bidAmount(uint48(block.timestamp)); // enforces auction ongoing

150:         amountIn = bidAmount(uint48(block.timestamp)); // enforces auction ongoing

184:         soldAmt = sellAmount > sellBal ? sellAmount - sellBal : 0;

218:         slippage = origin.maxTradeSlippage(); // {1}

218:         slippage = origin.maxTradeSlippage(); // {1}

220:         if (auctionVolume > maxTradeVolume) return 0; // 0% slippage beyond maxTradeVolume

220:         if (auctionVolume > maxTradeVolume) return 0; // 0% slippage beyond maxTradeVolume

225:                 FIX_ONE - divuu(auctionVolume - minTradeVolume, maxTradeVolume - minTradeVolume)

225:                 FIX_ONE - divuu(auctionVolume - minTradeVolume, maxTradeVolume - minTradeVolume)

225:                 FIX_ONE - divuu(auctionVolume - minTradeVolume, maxTradeVolume - minTradeVolume)

237:         uint192 progression = divuu(timestamp - startTime, endTime - startTime); // {1}

237:         uint192 progression = divuu(timestamp - startTime, endTime - startTime); // {1}

237:         uint192 progression = divuu(timestamp - startTime, endTime - startTime); // {1}

237:         uint192 progression = divuu(timestamp - startTime, endTime - startTime); // {1}

241:             uint192 exp = MAX_EXP.mulDiv(FORTY_PERCENT - progression, FORTY_PERCENT, ROUND);

252:             middlePrice -

253:             (middlePrice - lowPrice).mulDiv(progression - FORTY_PERCENT, SIXTY_PERCENT);

253:             (middlePrice - lowPrice).mulDiv(progression - FORTY_PERCENT, SIXTY_PERCENT);
File: contracts/plugins/trading/GnosisTrade.sol

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

4: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

5: import "@openzeppelin/contracts/utils/math/Math.sol";

5: import "@openzeppelin/contracts/utils/math/Math.sol";

5: import "@openzeppelin/contracts/utils/math/Math.sol";

5: import "@openzeppelin/contracts/utils/math/Math.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

6: import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

7: import "../../libraries/Fixed.sol";

7: import "../../libraries/Fixed.sol";

7: import "../../libraries/Fixed.sol";

8: import "../../interfaces/IBroker.sol";

8: import "../../interfaces/IBroker.sol";

8: import "../../interfaces/IBroker.sol";

9: import "../../interfaces/IGnosis.sol";

9: import "../../interfaces/IGnosis.sol";

9: import "../../interfaces/IGnosis.sol";

10: import "../../interfaces/ITrade.sol";

10: import "../../interfaces/ITrade.sol";

10: import "../../interfaces/ITrade.sol";

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

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

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

35:     IGnosis public gnosis; // Gnosis Auction contract

35:     IGnosis public gnosis; // Gnosis Auction contract

36:     uint256 public auctionId; // The Gnosis Auction ID returned by gnosis.initiateAuction()

36:     uint256 public auctionId; // The Gnosis Auction ID returned by gnosis.initiateAuction()

37:     IBroker public broker; // The Broker that cloned this contract into existence

37:     IBroker public broker; // The Broker that cloned this contract into existence

43:     IERC20Metadata public sell; // address of token this trade is selling

43:     IERC20Metadata public sell; // address of token this trade is selling

44:     IERC20Metadata public buy; // address of token this trade is buying

44:     IERC20Metadata public buy; // address of token this trade is buying

45:     uint256 public initBal; // {qTok}, this trade's balance of `sell` when init() was called

45:     uint256 public initBal; // {qTok}, this trade's balance of `sell` when init() was called

46:     uint48 public endTime; // timestamp after which this trade's auction can be settled

46:     uint48 public endTime; // timestamp after which this trade's auction can be settled

47:     uint192 public worstCasePrice; // {buyTok/sellTok}, the worst price we expect to get at Auction

47:     uint192 public worstCasePrice; // {buyTok/sellTok}, the worst price we expect to get at Auction

47:     uint192 public worstCasePrice; // {buyTok/sellTok}, the worst price we expect to get at Auction

97:         endTime = uint48(block.timestamp) + batchAuctionLength;

100:         worstCasePrice = shiftl_toFix(req.minBuyAmount, -int8(buy.decimals())).div(

101:             shiftl_toFix(req.sellAmount, -int8(sell.decimals()))

108:                 req.sellAmount * FEE_DENOMINATOR,

109:                 FEE_DENOMINATOR + gnosis.feeNumerator(),

115:         uint96 minBuyAmount = uint96(Math.max(1, req.minBuyAmount)); // Safe downcast; require'd

115:         uint96 minBuyAmount = uint96(Math.max(1, req.minBuyAmount)); // Safe downcast; require'd

118:             minBuyAmount / MAX_ORDERS,

190:             soldAmt = initBal - sellBal;

194:             uint256 adjustedBuyAmt = boughtAmt + 1;

197:             uint192 clearingPrice = shiftl_toFix(adjustedBuyAmt, -int8(buy.decimals())).div(

198:                 shiftl_toFix(adjustedSoldAmt, -int8(sell.decimals()))

[GAS-7] 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 (163):

File: contracts/libraries/Throttle.sol

53:             require(uint256(amount) <= available, "supply change throttled");
File: contracts/mixins/Auth.sol

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

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

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

215:         require(newUnfreezeAt > unfreezeAt, "frozen");
File: contracts/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: contracts/p1/AssetRegistry.sol

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

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

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

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

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

130:         require(assets[erc20].isCollateral(), "erc20 is not collateral");

210:         require(gas > GAS_TO_RESERVE, "not enough gas to unregister safely");
File: contracts/p1/BackingManager.sol

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

116:         require(tradesOpen == 0, "trade open");

117:         require(basketHandler.isReady(), "basket not ready");

118:         require(block.timestamp >= basketHandler.timestamp() + tradingDelay, "trading delayed");

121:         require(basketsHeld.bottom < rToken.basketsNeeded(), "already collateralized");

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

180:         require(tradesOpen == 0, "trade open");

181:         require(basketHandler.isReady(), "basket not ready");

182:         require(block.timestamp >= basketHandler.timestamp() + tradingDelay, "trading delayed");

183:         require(basketsHeld.bottom >= rToken.basketsNeeded(), "undercollateralized");

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

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

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

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

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

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

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

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

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

389:         require(basketNonces.length == portions.length, "portions does not mirror basketNonces");

398:             require(basketNonces[i] <= nonce, "invalid basketNonce");

493:         require(val >= MIN_WARMUP_PERIOD && val <= MAX_WARMUP_PERIOD, "invalid warmupPeriod");

557:             require(contains && amt >= newTargetAmts[i], "new basket adds target weights");

561:         require(_targetAmts.length() == 0, "new basket missing target weights");

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

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

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

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

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

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

120:         require(trades[_msgSender()], "unrecognized trade contract");

129:         require(address(newGnosis) != address(0), "invalid Gnosis address");

188:         require(batchAuctionLength > 0, "batch auctions not enabled");

212:         require(dutchAuctionLength > 0, "dutch auctions not enabled");
File: contracts/p1/Deployer.sol

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

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

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

158:         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 <= MAX_DISTRIBUTION, "RSR distribution too high");

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

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

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

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

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

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

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

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

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

102:         require(amount > 0, "Cannot issue zero");

113:         require(basketHandler.isReady(), "basket not ready");

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

189:         require(amount <= balanceOf(_msgSender()), "insufficient balance");

190:         require(basketHandler.fullyCollateralized(), "partial redemption; use redeemCustom");

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

262:         require(amount <= balanceOf(_msgSender()), "insufficient balance");

267:         require(portionsSum == FIX_ONE, "portions do not add up to FIX_ONE");

327:             if (allZero) revert("empty redemption");

336:             require(bal - pastBals[i] >= minAmounts[i], "redemption below minimum");

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

365:         require(_msgSender() == address(furnace), "furnace only");

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

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

396:         require(supply > 0, "0 supply");

405:         require(low >= MIN_EXCHANGE_RATE && high <= MAX_EXCHANGE_RATE, "BU rate out of range");

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

445:         require(params.amtRate >= MIN_THROTTLE_RATE_AMT, "issuance amtRate too small");

446:         require(params.amtRate <= MAX_THROTTLE_RATE_AMT, "issuance amtRate too big");

447:         require(params.pctRate <= MAX_THROTTLE_PCT_AMT, "issuance pctRate too big");

454:         require(params.amtRate >= MIN_THROTTLE_RATE_AMT, "redemption amtRate too small");

455:         require(params.amtRate <= MAX_THROTTLE_RATE_AMT, "redemption amtRate too big");

456:         require(params.pctRate <= MAX_THROTTLE_PCT_AMT, "redemption pctRate too big");

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

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

111:         require(address(trades[erc20]) == address(0), "trade open");

112:         require(erc20.balanceOf(address(this)) > 0, "0 balance");

117:         require(buyPrice > 0 && buyPrice < FIX_MAX, "buy asset price unknown");

135:         require(req.sellAmount > 1, "sell amount too low");
File: contracts/p1/StRSR.sol

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

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

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

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

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

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

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

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

336:         require(basketHandler.isReady(), "basket not ready");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

931:         require(val > MIN_UNSTAKING_DELAY && val <= MAX_UNSTAKING_DELAY, "invalid unstakingDelay");

940:         require(val <= MAX_REWARD_RATIO, "invalid rewardRatio");

948:         require(val <= MAX_WITHDRAWAL_LEAK, "invalid withdrawalLeak");
File: contracts/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 == _useDelegationNonce(signer), "ERC20Votes: invalid nonce");
File: contracts/p1/mixins/Component.sol

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

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

47:         require(!main.issuancePausedOrFrozen(), "frozen or issuance paused");

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

57:         require(main.hasRole(OWNER, _msgSender()), "governance only");
File: contracts/p1/mixins/Trading.sol

89:         require(address(trade) != address(0), "no trade open");

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

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

139:         require(val <= MAX_TRADE_VOLUME, "invalid minTradeVolume");
File: contracts/plugins/governance/Governance.sol

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

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

131:         require(startedInSameEra(proposalId), "new era");
File: contracts/plugins/trading/DutchTrade.sol

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

83:         require(timestamp >= startTime, "auction not started");

84:         require(timestamp <= endTime, "auction over");

116:         require(sellLow > 0 && sellHigh < FIX_MAX, "bad sell pricing");

117:         require(buyLow > 0 && buyHigh < FIX_MAX, "bad buy pricing");

123:         require(sellAmount_ <= sell.balanceOf(address(this)), "unfunded trade");

147:         require(bidder == address(0), "bid already received");

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

180:             require(block.timestamp >= endTime, "auction not over");

196:         require(status == TradeStatus.CLOSED, "only after trade is closed");
File: contracts/plugins/trading/GnosisTrade.sol

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

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

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

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

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

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

211:         require(status == TradeStatus.CLOSED, "only after trade is closed");

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

Instances (52):

File: contracts/libraries/Array.sol

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

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

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

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

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

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

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

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

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

119:         for (uint256 i = 0; i < len; ++i) refAmts[i] = basket.refAmts[basket.erc20s[i]];

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

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

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

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

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

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

397:         for (uint48 i = 0; i < basketNonces.length; ++i) {

402:             for (uint256 j = 0; j < b.erc20s.length; ++j) {

408:                 for (uint256 k = 0; k < len; ++k) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

264:         for (uint256 i = 0; i < portions.length; ++i) {

292:         for (uint256 i = 0; i < erc20sOut.length; ++i) {

306:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {

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

333:         for (uint256 i = 0; i < expectedERC20sOut.length; ++i) {
File: contracts/p1/StRSRVotes.sol

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

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

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

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

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

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

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

248:             for (uint256 j = 0; j < backup.erc20s.length && size < backup.max; ++j) {

256:             uint256 assigned = 0;

259:             for (uint256 j = 0; j < backup.erc20s.length && assigned < size; ++j) {
File: contracts/p1/mixins/RecollateralizationLib.sol

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

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

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

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

[GAS-9] Long revert strings

Instances (16):

File: contracts/p1/AssetRegistry.sol

210:         require(gas > GAS_TO_RESERVE, "not enough gas to unregister safely");
File: contracts/p1/BasketHandler.sol

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

389:         require(basketNonces.length == portions.length, "portions does not mirror basketNonces");

561:         require(_targetAmts.length() == 0, "new basket missing target weights");

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

190:         require(basketHandler.fullyCollateralized(), "partial redemption; use redeemCustom");

267:         require(portionsSum == FIX_ONE, "portions do not add up to FIX_ONE");
File: contracts/p1/StRSR.sol

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

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

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

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

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

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

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

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

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

[GAS-10] 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 (14):

File: contracts/mixins/Auth.sol

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

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

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

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

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

169:     function pauseTrading() external onlyRole(PAUSER) {

176:     function unpauseTrading() external onlyRole(PAUSER) {

183:     function pauseIssuance() external onlyRole(PAUSER) {

190:     function unpauseIssuance() external onlyRole(PAUSER) {

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

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

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

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

33:     function __Component_init(IMain main_) internal onlyInitializing {

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

Saves 5 gas per loop

Instances (11):

File: contracts/libraries/Fixed.sol

165:             result++;

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

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

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

124:             numTransfers++;

129:         for (uint256 i = 0; i < numTransfers; i++) {
File: contracts/p1/StRSR.sol

640:         era++;

652:         draftEra++;
File: contracts/p1/mixins/BasketLib.sol

249:                 if (goodCollateral(targetNames.at(i), backup.erc20s[j], assetRegistry)) size++;

271:                     assigned++;
File: contracts/p1/mixins/Trading.sol

123:         tradesOpen++;

[GAS-12] 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 (36):

File: contracts/mixins/Auth.sol

29:     bytes32 public constant OWNER_ROLE = OWNER;

30:     bytes32 public constant SHORT_FREEZER_ROLE = SHORT_FREEZER;

31:     bytes32 public constant LONG_FREEZER_ROLE = LONG_FREEZER;

32:     bytes32 public constant PAUSER_ROLE = PAUSER;
File: contracts/p1/AssetRegistry.sol

15:     uint256 public constant GAS_TO_RESERVE = 900000; // just enough to disable basket on n=128
File: contracts/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: contracts/p1/BasketHandler.sol

27:     uint192 public constant MAX_TARGET_AMT = 1e3 * FIX_ONE; // {target/BU} max basket weight

28:     uint48 public constant MIN_WARMUP_PERIOD = 60; // {s} 1 minute

29:     uint48 public constant MAX_WARMUP_PERIOD = 31536000; // {s} 1 year
File: contracts/p1/Broker.sol

25:     uint48 public constant MAX_AUCTION_LENGTH = 604800; // {s} max valid duration - 1 week

26:     uint48 public constant MIN_AUCTION_LENGTH = ONE_BLOCK * 2; // {s} min auction length - 2 blocks
File: contracts/p1/Deployer.sol

31:     string public constant ENS = "reserveprotocol.eth";
File: contracts/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 = MAX_DESTINATIONS; // 100
File: contracts/p1/Furnace.sol

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

16:     uint48 public constant PERIOD = ONE_BLOCK; // {s} 12 seconds; 1 block on PoS Ethereum
File: contracts/p1/RToken.sol

22:     uint256 public constant MIN_THROTTLE_RATE_AMT = 1e18; // {qRTok}

23:     uint256 public constant MAX_THROTTLE_RATE_AMT = 1e48; // {qRTok}

24:     uint192 public constant MAX_THROTTLE_PCT_AMT = 1e18; // {qRTok}

25:     uint192 public constant MIN_EXCHANGE_RATE = 1e9; // D18{BU/rTok}

26:     uint192 public constant MAX_EXCHANGE_RATE = 1e27; // D18{BU/rTok}
File: contracts/p1/StRSR.sol

37:     uint48 public constant PERIOD = ONE_BLOCK; // {s} 12 seconds; 1 block on PoS Ethereum

38:     uint48 public constant MIN_UNSTAKING_DELAY = PERIOD * 2; // {s}

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

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

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

23:     uint192 public constant MAX_TRADE_VOLUME = 1e29; // {UoA}

24:     uint192 public constant MAX_TRADE_SLIPPAGE = 1e18; // {%}
File: contracts/plugins/governance/Governance.sol

31:     uint256 public constant ONE_HUNDRED_PERCENT = 1e8; // {micro %}
File: contracts/plugins/trading/DutchTrade.sol

45:     TradeKind public constant KIND = TradeKind.DUTCH_AUCTION;
File: contracts/plugins/trading/GnosisTrade.sol

20:     TradeKind public constant KIND = TradeKind.BATCH_AUCTION;

21:     uint256 public constant FEE_DENOMINATOR = 1000;

25:     uint96 public constant MAX_ORDERS = 1e5;

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

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

Instances (5):

File: contracts/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;

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

[GAS-14] Splitting require() statements that use && saves gas

Instances (10):

File: contracts/mixins/Auth.sol

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

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

493:         require(val >= MIN_WARMUP_PERIOD && val <= MAX_WARMUP_PERIOD, "invalid warmupPeriod");

557:             require(contains && amt >= newTargetAmts[i], "new basket adds target weights");
File: contracts/p1/Deployer.sol

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

405:         require(low >= MIN_EXCHANGE_RATE && high <= MAX_EXCHANGE_RATE, "BU rate out of range");
File: contracts/p1/RevenueTrader.sol

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

931:         require(val > MIN_UNSTAKING_DELAY && val <= MAX_UNSTAKING_DELAY, "invalid unstakingDelay");
File: contracts/plugins/trading/DutchTrade.sol

116:         require(sellLow > 0 && sellHigh < FIX_MAX, "bad sell pricing");

117:         require(buyLow > 0 && buyHigh < FIX_MAX, "bad buy pricing");

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

Instances (63):

File: contracts/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) {

589:         if (mm > 0) result += 1;
File: contracts/libraries/Throttle.sol

52:         if (amount > 0) {
File: contracts/mixins/Auth.sol

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

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

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

90:             if (quantity > 0) basketHandler.disableBasket(); // not an interaction

107:             if (quantity > 0) basketHandler.disableBasket(); // not an interaction
File: contracts/p1/BackingManager.sol

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

241:                 if (totals.rsrTotal > 0) {

244:                 if (totals.rTokenTotal > 0) {
File: contracts/p1/BasketHandler.sol

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

182:         if (config.erc20s.length > 0) requireConstantConfigTargets(erc20s, targetAmts);

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

535:         while (_targetAmts.length() > 0) {
File: contracts/p1/Broker.sol

188:         require(batchAuctionLength > 0, "batch auctions not enabled");

212:         require(dutchAuctionLength > 0, "dutch auctions not enabled");
File: contracts/p1/Distributor.sol

94:             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: contracts/p1/Furnace.sol

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

86:         if (lastPayout > 0) try this.melt() {} catch {}
File: contracts/p1/RToken.sol

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

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

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

102:         require(amount > 0, "Cannot issue zero");

131:         uint192 amtBaskets = supply > 0

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

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

396:         require(supply > 0, "0 supply");

478:         uint256 amtRToken = totalSupply > 0
File: contracts/p1/RevenueTrader.sol

112:         require(erc20.balanceOf(address(this)) > 0, "0 balance");

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

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

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

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

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

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

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

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

437:         if (stakeRSR > 0) {

452:         if (draftRSR > 0) {

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

622:         uint64 lastAvailableAt = index > 0 ? queue[index - 1].availableAt : 0;
File: contracts/p1/StRSRVotes.sol

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

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

136:        If unsoundPrimeWt(tgt) > 0 and len(backups(tgt)) == 0 for some tgt, then return false.

168:         while (targetNames.length() > 0) targetNames.remove(targetNames.at(0));

279:         return newBasket.erc20s.length > 0;

302:                 coll.refPerTok() > 0 &&

303:                 coll.targetPerRef() > 0;
File: contracts/p1/mixins/RecollateralizationLib.sol

405:                 high > 0 &&
File: contracts/p1/mixins/TradeLib.sol

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

114:             trade.sellPrice > 0 &&

116:                 trade.buyPrice > 0 &&

182:         return size > 0 ? size : 1;

197:         return size > 0 ? size : 1;
File: contracts/plugins/trading/DutchTrade.sol

116:         require(sellLow > 0 && sellHigh < FIX_MAX, "bad sell pricing");

117:         require(buyLow > 0 && buyHigh < FIX_MAX, "bad buy pricing");
File: contracts/plugins/trading/GnosisTrade.sol

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

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

[GAS-16] internal functions not called by the contract should be removed

If the functions are required by an interface, the contract should inherit from that interface and use the override keyword

Instances (29):

File: contracts/interfaces/IAsset.sol

86:     function worseThan(CollateralStatus a, CollateralStatus b) internal pure returns (bool) {
File: contracts/libraries/Array.sol

9:     function allUnique(IERC20[] memory arr) internal pure returns (bool) {

21:     function sortedAndAllUnique(IERC20[] memory arr) internal pure returns (bool) {
File: contracts/libraries/Fixed.sol

222:     function plus(uint192 x, uint192 y) internal pure returns (uint192) {

229:     function plusu(uint192 x, uint256 y) internal pure returns (uint192) {

236:     function minus(uint192 x, uint192 y) internal pure returns (uint192) {

243:     function minusu(uint192 x, uint256 y) internal pure returns (uint192) {

269:     function mulu(uint192 x, uint256 y) internal pure returns (uint192) {

316:     function powu(uint192 x_, uint48 y) internal pure returns (uint192) {

332:     function lt(uint192 x, uint192 y) internal pure returns (bool) {

336:     function lte(uint192 x, uint192 y) internal pure returns (bool) {

340:     function gt(uint192 x, uint192 y) internal pure returns (bool) {

344:     function gte(uint192 x, uint192 y) internal pure returns (bool) {

348:     function eq(uint192 x, uint192 y) internal pure returns (bool) {

352:     function neq(uint192 x, uint192 y) internal pure returns (bool) {

359:     function near(

401:     function mulu_toUint(uint192 x, uint256 y) internal pure returns (uint256) {

408:     function mulu_toUint(

419:     function mul_toUint(uint192 x, uint192 y) internal pure returns (uint256) {

426:     function mul_toUint(

489:     function safeMul(
File: contracts/libraries/Permit.sol

10:     function requireSignature(
File: contracts/libraries/String.sol

11:     function toLower(string memory str) internal pure returns (string memory) {
File: contracts/libraries/Throttle.sol

37:     function useAvailable(
File: contracts/p1/mixins/BasketLib.sol

75:     function setFrom(Basket storage self, Basket storage other) internal {

87:     function add(
File: contracts/p1/mixins/RewardableLib.sol

25:     function claimRewards(IAssetRegistry reg) internal {

38:     function claimRewardsSingle(IAsset asset) internal {
File: contracts/p1/mixins/TradeLib.sol

108:     function prepareTradeToCoverDeficit(

Non Critical Issues

Issue Instances
NC-1 require() / revert() statements should have descriptive reason strings 1
NC-2 Return values of approve() not checked 5
NC-3 Event is missing indexed fields 11
NC-4 Constants should be defined rather than using magic numbers 5
NC-5 Functions not used internally could be marked external 84

[NC-1] require() / revert() statements should have descriptive reason strings

Instances (1):

File: contracts/libraries/Fixed.sol

317:         require(x_ <= FIX_ONE);

[NC-2] 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 (5):

File: contracts/p1/StRSR.sol

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

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

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

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

898:         _approve(owner, spender, value);

[NC-3] Event is missing indexed fields

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

File: contracts/interfaces/IBasketHandler.sol

26:     event PrimeBasketSet(IERC20[] erc20s, uint192[] targetAmts, bytes32[] targetNames);

33:     event BasketSet(uint256 indexed nonce, IERC20[] erc20s, uint192[] refAmts, bool disabled);

39:     event BackupConfigSet(bytes32 indexed targetName, uint256 indexed max, IERC20[] erc20s);
File: contracts/interfaces/IDeployerRegistry.sol

7:     event DeploymentUnregistered(string version, IDeployer deployer);

8:     event DeploymentRegistered(string version, IDeployer deployer);

9:     event LatestChanged(string version, IDeployer deployer);
File: contracts/interfaces/IDistributor.sol

31:     event DistributionSet(address dest, uint16 rTokenDist, uint16 rsrDist);
File: contracts/interfaces/IRToken.sol

48:     event BasketsNeededChanged(uint192 oldBasketsNeeded, uint192 newBasketsNeeded);

52:     event Melted(uint256 amount);

55:     event IssuanceThrottleSet(ThrottleLib.Params oldVal, ThrottleLib.Params newVal);

58:     event RedemptionThrottleSet(ThrottleLib.Params oldVal, ThrottleLib.Params newVal);

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

Instances (5):

File: contracts/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();
File: contracts/plugins/trading/DutchTrade.sol

20: uint192 constant BASE = 999999e12; // {1} (999999/1000000)

57:     uint48 public startTime; // {s} when the dutch auction begins (12s after init())

[NC-5] Functions not used internally could be marked external

Instances (84):

File: contracts/libraries/test/ArrayCallerMock.sol

8:     function allUnique(IERC20[] memory arr) public pure returns (bool) {

12:     function sortedAndAllUnique(IERC20[] memory arr) public pure returns (bool) {
File: contracts/libraries/test/FixedCallerMock.sol

9:     function toFix_(uint256 x) public pure returns (uint192 ) {

12:     function shiftl_toFix_(uint256 x, int8 d) public pure returns (uint192 ) {

15:     function shiftl_toFix_Rnd(uint256 x, int8 d, RoundingMode rnd) public pure returns (uint192 ) {

18:     function divFix_(uint256 x, uint192  y) public pure returns (uint192 ) {

21:     function divuu_(uint256 x, uint256 y) public pure returns (uint256) {

24:     function fixMin_(uint192  x, uint192  y) public pure returns (uint192 ) {

27:     function fixMax_(uint192  x, uint192  y) public pure returns (uint192 ) {

30:     function abs_(int256 x) public pure returns (uint256) {

33:     function divrnd_(uint256 n, uint256 d, RoundingMode rnd) public pure returns (uint256) {

36:     function toUint(uint192  x) public pure returns (uint256 ) {

39:     function toUintRnd(uint192  x, RoundingMode rnd) public pure returns (uint256 ) {

42:     function shiftl(uint192  x, int8 decimals) public pure returns (uint192 ) {

45:     function shiftlRnd(uint192  x, int8 decimals, RoundingMode rnd) public pure returns (uint192 ) {

48:     function plus(uint192  x, uint192  y) public pure returns (uint192 ) {

51:     function plusu(uint192  x, uint256 y) public pure returns (uint192 ) {

54:     function minus(uint192  x, uint192  y) public pure returns (uint192 ) {

57:     function minusu(uint192  x, uint256 y) public pure returns (uint192 ) {

60:     function mul(uint192  x, uint192  y) public pure returns (uint192 ) {

63:     function mulRnd(uint192  x, uint192  y, RoundingMode rnd) public pure returns (uint192 ) {

66:     function mulu(uint192  x, uint256 y) public pure returns (uint192 ) {

69:     function div(uint192  x, uint192  y) public pure returns (uint192 ) {

72:     function divRnd(uint192  x, uint192  y, RoundingMode rnd) public pure returns (uint192 ) {

75:     function divu(uint192  x, uint256 y) public pure returns (uint192 ) {

78:     function divuRnd(uint192  x, uint256 y, RoundingMode rnd) public pure returns (uint192 ) {

81:     function powu(uint192  x, uint48 y) public pure returns (uint192 ) {

84:     function lt(uint192  x, uint192  y) public pure returns (bool) {

87:     function lte(uint192  x, uint192  y) public pure returns (bool) {

90:     function gt(uint192  x, uint192  y) public pure returns (bool) {

93:     function gte(uint192  x, uint192  y) public pure returns (bool) {

96:     function eq(uint192  x, uint192  y) public pure returns (bool) {

99:     function neq(uint192  x, uint192  y) public pure returns (bool) {

102:     function near(uint192  x, uint192  y, uint192  epsilon) public pure returns (bool) {

107:     function shiftl_toUint(uint192  x, int8 d) public pure returns (uint256) {

110:     function shiftl_toUintRnd(uint192  x, int8 d, RoundingMode rnd) public pure returns (uint256) {

113:     function mulu_toUint(uint192  x, uint256 y) public pure returns (uint256) {

116:     function mulu_toUintRnd(uint192  x, uint256 y, RoundingMode rnd) public pure returns (uint256) {

119:     function mul_toUint(uint192  x, uint192  y) public pure returns (uint256) {

122:     function mul_toUintRnd(uint192  x, uint192  y, RoundingMode rnd) public pure returns (uint256) {

125:     function muluDivu(uint192  x, uint256 y, uint256 z) public pure returns (uint192 ) {

128:     function muluDivuRnd(uint192  x, uint256 y, uint256 z, RoundingMode rnd) public pure returns (uint192 ) {

131:     function mulDiv(uint192  x, uint192  y, uint192  z) public pure returns (uint192 ) {

134:     function mulDivRnd(uint192  x, uint192  y, uint192  z, RoundingMode rnd) public pure returns (uint192 ) {

138:     function safeMul_(uint192 a, uint192 b, RoundingMode rnd) public pure returns (uint192) {

143:     function mulDiv256_(uint256 x, uint256 y, uint256 z) public pure returns (uint256) {

146:     function mulDiv256Rnd_(uint256 x, uint256 y, uint256 z, RoundingMode rnd)

150:     function fullMul_(uint256 x, uint256 y) public pure returns (uint256 h, uint256 l) {
File: contracts/mixins/Auth.sol

87:     function grantRole(bytes32 role, address account)

99:     function frozen() public view returns (bool) {

105:     function tradingPausedOrFrozen() public view returns (bool) {

111:     function issuancePausedOrFrozen() public view returns (bool) {
File: contracts/p1/AssetRegistry.sol

56:     function refresh() public {
File: contracts/p1/BackingManager.sol

78:     function settleTrade(IERC20 sell)
File: contracts/p1/BasketHandler.sol

287:     function quantityUnsafe(IERC20 erc20, IAsset asset) public view returns (uint192) {
File: contracts/p1/Main.sol

53:     function hasRole(bytes32 role, address account)
File: contracts/p1/RToken.sol

92:     function issue(uint256 amount) public {
File: contracts/p1/RevenueTrader.sol

43:     function settleTrade(IERC20 sell)
File: contracts/p1/StRSR.sol

222:     function stake(uint256 rsrAmount) public {

719:     function totalSupply() public view returns (uint256) {

723:     function balanceOf(address account) public view returns (uint256) {

737:     function transfer(address to, uint256 amount) public returns (bool) {

747:     function approve(address spender, uint256 amount) public returns (bool) {

756:     function transferFrom(

766:     function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {

772:     function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {

881:     function permit(

901:     function nonces(address owner) public view returns (uint256) {

905:     function delegationNonces(address owner) public view returns (uint256) {
File: contracts/p1/StRSRVotes.sol

59:     function checkpoints(address account, uint48 pos) public view returns (Checkpoint memory) {

63:     function numCheckpoints(address account) public view returns (uint48) {

71:     function getVotes(address account) public view returns (uint256) {

76:     function getPastVotes(address account, uint256 blockNumber) public view returns (uint256) {

82:     function getPastTotalSupply(uint256 blockNumber) public view returns (uint256) {

88:     function getPastEra(uint256 blockNumber) public view returns (uint256) {

114:     function delegate(address delegatee) public {

118:     function delegateBySig(
File: contracts/plugins/governance/Governance.sol

51:     function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) {

55:     function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) {

60:     function proposalThreshold()

84:     function state(uint256 proposalId)

93:     function propose(

103:     function queue(

161:     function supportsInterface(bytes4 interfaceId)

Low Issues

Issue Instances
L-1 Do not use deprecated library functions 8
L-2 Empty Function Body - Consider commenting why 19
L-3 Initializers could be front-run 75

[L-1] Do not use deprecated library functions

Instances (8):

File: contracts/p1/BackingManager.sol

69:         IERC20(address(erc20)).safeApprove(address(main.rToken()), 0);

70:         IERC20(address(erc20)).safeApprove(address(main.rToken()), type(uint256).max);
File: contracts/p1/RevenueTrader.sol

59:         tokenToBuy.safeApprove(address(distributor), 0);

60:         tokenToBuy.safeApprove(address(distributor), bal);
File: contracts/p1/mixins/Trading.sol

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

119:         IERC20Upgradeable(address(sell)).safeApprove(address(broker), req.sellAmount);
File: contracts/plugins/trading/GnosisTrade.sol

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

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

[L-2] Empty Function Body - Consider commenting why

Instances (19):

File: contracts/p1/BackingManager.sol

89:             try this.rebalance(trade.KIND()) {} catch (bytes memory errData) {
File: contracts/p1/Furnace.sol

86:         if (lastPayout > 0) try this.melt() {} catch {}

86:         if (lastPayout > 0) try this.melt() {} catch {}
File: contracts/p1/Main.sol

23:     constructor() initializer {}

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

184:         try main.furnace().melt() {} catch {} // nice for the redeemer, but not necessary

184:         try main.furnace().melt() {} catch {} // nice for the redeemer, but not necessary

257:         try main.furnace().melt() {} catch {}

257:         try main.furnace().melt() {} catch {}
File: contracts/p1/StRSR.sol

705:     function requireNotTradingPausedOrFrozen() private notTradingPausedOrFrozen {}

709:     function requireNotFrozen() private notFrozen {}

713:     function requireGovernanceOnly() private governance {}
File: contracts/p1/mixins/Component.sol

25:     constructor() initializer {}

62:     function _authorizeUpgrade(address newImplementation) internal view override governance {}
File: contracts/p1/mixins/RewardableLib.sol

30:             try IRewardable(address(registry.erc20s[i])).claimRewards() {} catch {}

30:             try IRewardable(address(registry.erc20s[i])).claimRewards() {} catch {}

41:         try IRewardable(address(asset.erc20())).claimRewards() {} catch {}

41:         try IRewardable(address(asset.erc20())).claimRewards() {} catch {}
File: contracts/plugins/governance/Governance.sol

47:     {}

[L-3] Initializers could be front-run

Initializers could be front-run, allowing an attacker to either set their own values, take ownership of the contract, and in the best case forcing a re-deployment

Instances (75):

File: contracts/interfaces/IAssetRegistry.sol

34:     function init(IMain main_, IAsset[] memory assets_) external;
File: contracts/interfaces/IBackingManager.sol

29:     function init(
File: contracts/interfaces/IBasketHandler.sol

55:     function init(IMain main_, uint48 warmupPeriod_) external;
File: contracts/interfaces/IBroker.sol

36:     function init(
File: contracts/interfaces/IDistributor.sol

40:     function init(IMain main_, RevenueShare memory dist) external;
File: contracts/interfaces/IFurnace.sol

13:     function init(IMain main_, uint192 ratio_) external;
File: contracts/interfaces/IMain.sol

173:     function init(
File: contracts/interfaces/IRToken.sol

61:     function init(
File: contracts/interfaces/IRevenueTrader.sol

16:     function init(
File: contracts/interfaces/IStRSR.sol

101:     function init(
File: contracts/interfaces/ITrade.sol

8:     NOT_STARTED, // before init()

9:     OPEN, // after init() and before settle()

12:     PENDING // during init() or settle() (reentrancy protection)
File: contracts/mixins/Auth.sol

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

69:         __AccessControl_init();
File: contracts/mixins/ComponentRegistry.sol

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

41:     function init(IMain main_, IAsset[] calldata assets_) external initializer {

41:     function init(IMain main_, IAsset[] calldata assets_) external initializer {

42:         __Component_init(main_);
File: contracts/p1/BackingManager.sol

46:     function init(

52:     ) external initializer {

53:         __Component_init(main_);

54:         __Trading_init(main_, maxTradeSlippage_, minTradeVolume_);
File: contracts/p1/BasketHandler.sol

92:     function init(IMain main_, uint48 warmupPeriod_) external initializer {

92:     function init(IMain main_, uint48 warmupPeriod_) external initializer {

93:         __Component_init(main_);
File: contracts/p1/Broker.sol

63:     function init(

70:     ) external initializer {

71:         __Component_init(main_);

207:         trade.init(this, caller, gnosis, batchAuctionLength, req);

223:         trade.init(caller, req.sell, req.buy, req.sellAmount, dutchAuctionLength);
File: contracts/p1/Deployer.sol

174:         main.init(components, rsr, params.shortFreeze, params.longFreeze);

177:         components.backingManager.init(

186:         components.basketHandler.init(main, params.warmupPeriod);

189:         components.rsrTrader.init(main, rsr, params.maxTradeSlippage, params.minTradeVolume);

190:         components.rTokenTrader.init(

198:         components.distributor.init(main, params.dist);

201:         components.furnace.init(main, params.rewardRatio);

203:         components.broker.init(

216:             main.stRSR().init(

227:         components.rToken.init(

242:         components.assetRegistry.init(main, assets);
File: contracts/p1/Distributor.sol

41:     function init(IMain main_, RevenueShare calldata dist) external initializer {

41:     function init(IMain main_, RevenueShare calldata dist) external initializer {

42:         __Component_init(main_);
File: contracts/p1/Furnace.sol

34:     function init(IMain main_, uint192 ratio_) external initializer {

34:     function init(IMain main_, uint192 ratio_) external initializer {

35:         __Component_init(main_);
File: contracts/p1/Main.sol

23:     constructor() initializer {}

26:     function init(

31:     ) public virtual initializer {

33:         __Auth_init(shortFreeze_, longFreeze_);

34:         __ComponentRegistry_init(components);

35:         __UUPSUpgradeable_init();
File: contracts/p1/RToken.sol

61:     function init(

68:     ) external initializer {

72:         __Component_init(main_);

73:         __ERC20_init(name_, symbol_);

74:         __ERC20Permit_init(name_);
File: contracts/p1/RevenueTrader.sol

26:     function init(

31:     ) external initializer {

33:         __Component_init(main_);

34:         __Trading_init(main_, maxTradeSlippage_, minTradeVolume_);
File: contracts/p1/StRSR.sol

169:     function init(

176:     ) external initializer {

179:         __Component_init(main_);

180:         __EIP712_init(name_, VERSION);
File: contracts/p1/mixins/Component.sol

25:     constructor() initializer {}

33:     function __Component_init(IMain main_) internal onlyInitializing {

35:         __UUPSUpgradeable_init();
File: contracts/p1/mixins/Trading.sol

47:     function __Trading_init(
File: contracts/plugins/trading/DutchTrade.sol

57:     uint48 public startTime; // {s} when the dutch auction begins (12s after init())

100:     function init(
File: contracts/plugins/trading/GnosisTrade.sol

45:     uint256 public initBal; // {qTok}, this trade's balance of `sell` when init() was called

75:     function init(

Medium Issues

Issue Instances
M-1 Centralization Risk for trusted owners 18

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

File: contracts/interfaces/IMain.sol

52: interface IAuth is IAccessControlUpgradeable {

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

16: abstract contract Auth is AccessControlUpgradeable, IAuth {

16: abstract contract Auth is AccessControlUpgradeable, IAuth {

90:         onlyRole(getRoleAdmin(role))

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

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

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

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

169:     function pauseTrading() external onlyRole(PAUSER) {

176:     function unpauseTrading() external onlyRole(PAUSER) {

183:     function pauseIssuance() external onlyRole(PAUSER) {

190:     function unpauseIssuance() external onlyRole(PAUSER) {

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

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

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

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

64:     function _authorizeUpgrade(address newImplementation) internal override onlyRole(OWNER) {}
@tbrent
Copy link

tbrent commented Oct 3, 2023

Acklowedged!

@0xean
Copy link

0xean commented Oct 4, 2023

Confirmed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment