Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 20 from a total of 20 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Swap | 16139773 | 700 days ago | IN | 0 ETH | 0.00279518 | ||||
Swap | 16116985 | 703 days ago | IN | 0 ETH | 0.00235126 | ||||
Swap | 16103568 | 705 days ago | IN | 0 ETH | 0.00204003 | ||||
Swap | 16099786 | 705 days ago | IN | 0 ETH | 0.00282103 | ||||
Swap | 16089027 | 707 days ago | IN | 0 ETH | 0.00218596 | ||||
Swap | 16088244 | 707 days ago | IN | 0 ETH | 0.00209148 | ||||
Swap | 16066796 | 710 days ago | IN | 0 ETH | 0.00208425 | ||||
Swap | 16063456 | 710 days ago | IN | 0 ETH | 0.00256047 | ||||
Swap | 16043905 | 713 days ago | IN | 0 ETH | 0.00240161 | ||||
Swap | 16019906 | 716 days ago | IN | 0 ETH | 0.00483959 | ||||
Swap | 16009579 | 718 days ago | IN | 0 ETH | 0.0018082 | ||||
Swap | 16009111 | 718 days ago | IN | 0 ETH | 0.00236565 | ||||
Swap | 16003688 | 719 days ago | IN | 0 ETH | 0.00230061 | ||||
Swap | 15998753 | 719 days ago | IN | 0 ETH | 0.00277375 | ||||
Swap | 15998728 | 719 days ago | IN | 0 ETH | 0.00283365 | ||||
Swap | 15998634 | 719 days ago | IN | 0 ETH | 0.00197679 | ||||
Swap | 15998632 | 719 days ago | IN | 0 ETH | 0.00199 | ||||
Swap | 15998615 | 719 days ago | IN | 0 ETH | 0.00309948 | ||||
Swap | 15998613 | 719 days ago | IN | 0 ETH | 0.00291274 | ||||
0x61010060 | 15998134 | 720 days ago | IN | 0 ETH | 0.12138762 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Operator
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.15; import {ReentrancyGuard} from "solmate/utils/ReentrancyGuard.sol"; import {ERC20} from "solmate/tokens/ERC20.sol"; import {TransferHelper} from "libraries/TransferHelper.sol"; import {FullMath} from "libraries/FullMath.sol"; import {IOperator} from "policies/interfaces/IOperator.sol"; import {IBondCallback} from "interfaces/IBondCallback.sol"; import {IBondSDA} from "interfaces/IBondSDA.sol"; import {RolesConsumer} from "modules/ROLES/OlympusRoles.sol"; import {ROLESv1} from "modules/ROLES/ROLES.v1.sol"; import {TRSRYv1} from "modules/TRSRY/TRSRY.v1.sol"; import {MINTRv1} from "modules/MINTR/MINTR.v1.sol"; import {PRICEv1} from "modules/PRICE/PRICE.v1.sol"; import {RANGEv1} from "modules/RANGE/RANGE.v1.sol"; import "src/Kernel.sol"; /// @title Olympus Range Operator /// @notice Olympus Range Operator (Policy) Contract /// @dev The Olympus Range Operator performs market operations to enforce OlympusDAO's OHM price range /// guidance policies against a specific reserve asset. The Operator is maintained by a keeper-triggered /// function on the Olympus Heart contract, which orchestrates state updates in the correct order to ensure /// market operations use up to date information. When the price of OHM against the reserve asset exceeds /// the cushion spread, the Operator deploys bond markets to support the price. The Operator also offers /// zero slippage swaps at prices dictated by the wall spread from the moving average. These market operations /// are performed up to a specific capacity before the market must stabilize to regenerate the capacity. contract Operator is IOperator, Policy, RolesConsumer, ReentrancyGuard { using TransferHelper for ERC20; using FullMath for uint256; // ========= STATE ========= // // Operator variables, defined in the interface on the external getter functions Status internal _status; Config internal _config; /// @notice Whether the Operator has been initialized bool public initialized; /// @notice Whether the Operator is active bool public active; // Modules PRICEv1 internal PRICE; RANGEv1 internal RANGE; TRSRYv1 internal TRSRY; MINTRv1 internal MINTR; // External contracts /// @notice Auctioneer contract used for cushion bond market deployments IBondSDA public auctioneer; /// @notice Callback contract used for cushion bond market payouts IBondCallback public callback; // Tokens /// @notice OHM token contract ERC20 public immutable ohm; uint8 public immutable ohmDecimals; /// @notice Reserve token contract ERC20 public immutable reserve; uint8 public immutable reserveDecimals; // Constants uint32 public constant ONE_HUNDRED_PERCENT = 100e2; uint32 public constant ONE_PERCENT = 1e2; //============================================================================================// // POLICY SETUP // //============================================================================================// constructor( Kernel kernel_, IBondSDA auctioneer_, IBondCallback callback_, ERC20[2] memory tokens_, // [ohm, reserve] uint32[8] memory configParams // [cushionFactor, cushionDuration, cushionDebtBuffer, cushionDepositInterval, reserveFactor, regenWait, regenThreshold, regenObserve] ensure the following holds: regenWait / PRICE.observationFrequency() >= regenObserve - regenThreshold ) Policy(kernel_) { // Check params are valid if (address(auctioneer_) == address(0) || address(callback_) == address(0)) revert Operator_InvalidParams(); if (configParams[1] > uint256(7 days) || configParams[1] < uint256(1 days)) revert Operator_InvalidParams(); if (configParams[2] < uint32(10e3)) revert Operator_InvalidParams(); if (configParams[3] < uint32(1 hours) || configParams[3] > configParams[1]) revert Operator_InvalidParams(); if (configParams[0] > ONE_HUNDRED_PERCENT || configParams[0] < ONE_PERCENT) revert Operator_InvalidParams(); if (configParams[4] > ONE_HUNDRED_PERCENT || configParams[4] < ONE_PERCENT) revert Operator_InvalidParams(); if ( configParams[5] < 1 hours || configParams[6] > configParams[7] || configParams[7] == uint32(0) || configParams[6] == uint32(0) ) revert Operator_InvalidParams(); auctioneer = auctioneer_; callback = callback_; ohm = tokens_[0]; ohmDecimals = tokens_[0].decimals(); reserve = tokens_[1]; reserveDecimals = tokens_[1].decimals(); Regen memory regen = Regen({ count: uint32(0), lastRegen: uint48(block.timestamp), nextObservation: uint32(0), observations: new bool[](configParams[7]) }); _config = Config({ cushionFactor: configParams[0], cushionDuration: configParams[1], cushionDebtBuffer: configParams[2], cushionDepositInterval: configParams[3], reserveFactor: configParams[4], regenWait: configParams[5], regenThreshold: configParams[6], regenObserve: configParams[7] }); _status = Status({low: regen, high: regen}); emit CushionFactorChanged(configParams[0]); emit CushionParamsChanged(configParams[1], configParams[2], configParams[3]); emit ReserveFactorChanged(configParams[4]); emit RegenParamsChanged(configParams[5], configParams[6], configParams[7]); } /// @inheritdoc Policy function configureDependencies() external override returns (Keycode[] memory dependencies) { dependencies = new Keycode[](5); dependencies[0] = toKeycode("PRICE"); dependencies[1] = toKeycode("RANGE"); dependencies[2] = toKeycode("TRSRY"); dependencies[3] = toKeycode("MINTR"); dependencies[4] = toKeycode("ROLES"); PRICE = PRICEv1(getModuleAddress(dependencies[0])); RANGE = RANGEv1(getModuleAddress(dependencies[1])); TRSRY = TRSRYv1(getModuleAddress(dependencies[2])); MINTR = MINTRv1(getModuleAddress(dependencies[3])); ROLES = ROLESv1(getModuleAddress(dependencies[4])); // Approve MINTR for burning OHM (called here so that it is re-approved on updates) ohm.safeApprove(address(MINTR), type(uint256).max); } /// @inheritdoc Policy function requestPermissions() external view override returns (Permissions[] memory requests) { Keycode RANGE_KEYCODE = RANGE.KEYCODE(); Keycode TRSRY_KEYCODE = TRSRY.KEYCODE(); Keycode MINTR_KEYCODE = MINTR.KEYCODE(); requests = new Permissions[](13); requests[0] = Permissions(RANGE_KEYCODE, RANGE.updateCapacity.selector); requests[1] = Permissions(RANGE_KEYCODE, RANGE.updateMarket.selector); requests[2] = Permissions(RANGE_KEYCODE, RANGE.updatePrices.selector); requests[3] = Permissions(RANGE_KEYCODE, RANGE.regenerate.selector); requests[4] = Permissions(RANGE_KEYCODE, RANGE.setSpreads.selector); requests[5] = Permissions(RANGE_KEYCODE, RANGE.setThresholdFactor.selector); requests[6] = Permissions(TRSRY_KEYCODE, TRSRY.withdrawReserves.selector); requests[7] = Permissions(TRSRY_KEYCODE, TRSRY.increaseWithdrawApproval.selector); requests[8] = Permissions(TRSRY_KEYCODE, TRSRY.decreaseWithdrawApproval.selector); requests[9] = Permissions(MINTR_KEYCODE, MINTR.mintOhm.selector); requests[10] = Permissions(MINTR_KEYCODE, MINTR.burnOhm.selector); requests[11] = Permissions(MINTR_KEYCODE, MINTR.increaseMintApproval.selector); requests[12] = Permissions(MINTR_KEYCODE, MINTR.decreaseMintApproval.selector); } //============================================================================================// // CORE FUNCTIONS // //============================================================================================// /// @dev Checks to see if the policy is active and ensures the range data isn't stale before performing market operations. /// This check is different from the price feed staleness checks in the PRICE module. /// The PRICE module checks new price feed data for staleness when storing a new observations, /// whereas this check ensures that the range data is using a recent observation. modifier onlyWhileActive() { if ( !active || uint48(block.timestamp) > PRICE.lastObservationTime() + 3 * PRICE.observationFrequency() ) revert Operator_Inactive(); _; } // ========= HEART FUNCTIONS ========= // /// @inheritdoc IOperator function operate() external override onlyWhileActive onlyRole("operator_operate") { // Revert if not initialized if (!initialized) revert Operator_NotInitialized(); // Update the prices for the range, save new regen observations, and update capacities based on bond market activity _updateRangePrices(); _addObservation(); // Cache config in memory Config memory config_ = _config; // Check if walls can regenerate capacity if ( uint48(block.timestamp) >= RANGE.lastActive(true) + uint48(config_.regenWait) && _status.high.count >= config_.regenThreshold ) { _regenerate(true); } if ( uint48(block.timestamp) >= RANGE.lastActive(false) + uint48(config_.regenWait) && _status.low.count >= config_.regenThreshold ) { _regenerate(false); } // Cache range data after potential regeneration RANGEv1.Range memory range = RANGE.range(); // Get latest price // See note in addObservation() for more details uint256 currentPrice = PRICE.getLastPrice(); // Check if the cushion bond markets are active // if so, determine if it should stay open or close // if not, check if a new one should be opened if (range.low.active) { if (auctioneer.isLive(range.low.market)) { // if active, check if the price is back above the cushion // or if the price is below the wall // if so, close the market if (currentPrice > range.cushion.low.price || currentPrice < range.wall.low.price) { _deactivate(false); } } else { // if not active, check if the price is below the cushion // if so, open a new bond market if (currentPrice < range.cushion.low.price && currentPrice > range.wall.low.price) { _activate(false); } } } if (range.high.active) { if (auctioneer.isLive(range.high.market)) { // if active, check if the price is back under the cushion // or if the price is above the wall // if so, close the market if ( currentPrice < range.cushion.high.price || currentPrice > range.wall.high.price ) { _deactivate(true); } } else { // if not active, check if the price is above the cushion // if so, open a new bond market if ( currentPrice > range.cushion.high.price && currentPrice < range.wall.high.price ) { _activate(true); } } } } // ========= OPEN MARKET OPERATIONS (WALL) ========= // /// @inheritdoc IOperator function swap( ERC20 tokenIn_, uint256 amountIn_, uint256 minAmountOut_ ) external override onlyWhileActive nonReentrant returns (uint256 amountOut) { if (tokenIn_ == ohm) { // Revert if lower wall is inactive if (!RANGE.active(false)) revert Operator_WallDown(); // Calculate amount out (checks for sufficient capacity) amountOut = getAmountOut(tokenIn_, amountIn_); // Revert if amount out less than the minimum specified /// @dev even though price is fixed most of the time, /// it is possible that the amount out could change on a sender /// due to the wall prices being updated before their transaction is processed. /// This would be the equivalent of the heart.beat front-running the sender. if (amountOut < minAmountOut_) revert Operator_AmountLessThanMinimum(amountOut, minAmountOut_); // Decrement wall capacity _updateCapacity(false, amountOut); // If wall is down after swap, deactive the cushion as well _checkCushion(false); // Transfer OHM from sender ohm.safeTransferFrom(msg.sender, address(this), amountIn_); // Burn OHM MINTR.burnOhm(address(this), amountIn_); // Withdraw and transfer reserve to sender TRSRY.withdrawReserves(msg.sender, reserve, amountOut); emit Swap(ohm, reserve, amountIn_, amountOut); } else if (tokenIn_ == reserve) { // Revert if upper wall is inactive if (!RANGE.active(true)) revert Operator_WallDown(); // Calculate amount out (checks for sufficient capacity) amountOut = getAmountOut(tokenIn_, amountIn_); // Revert if amount out less than the minimum specified /// @dev even though price is fixed most of the time, /// it is possible that the amount out could change on a sender /// due to the wall prices being updated before their transaction is processed. /// This would be the equivalent of the heart.beat front-running the sender. if (amountOut < minAmountOut_) revert Operator_AmountLessThanMinimum(amountOut, minAmountOut_); // Decrement wall capacity _updateCapacity(true, amountOut); // If wall is down after swap, deactive the cushion as well _checkCushion(true); // Transfer reserves to treasury reserve.safeTransferFrom(msg.sender, address(TRSRY), amountIn_); // Mint OHM to sender MINTR.mintOhm(msg.sender, amountOut); emit Swap(reserve, ohm, amountIn_, amountOut); } else { revert Operator_InvalidParams(); } } // ========= BOND MARKET OPERATIONS (CUSHION) ========= // /// @notice Records a bond purchase and updates capacity correctly /// @notice Access restricted (BondCallback) /// @param id_ ID of the bond market /// @param amountOut_ Amount of capacity expended function bondPurchase(uint256 id_, uint256 amountOut_) external onlyWhileActive onlyRole("operator_reporter") { if (id_ == RANGE.market(true)) { _updateCapacity(true, amountOut_); _checkCushion(true); } if (id_ == RANGE.market(false)) { _updateCapacity(false, amountOut_); _checkCushion(false); } } /// @notice Activate a cushion by deploying a bond market /// @param high_ Whether the cushion is for the high or low side of the range (true = high, false = low) function _activate(bool high_) internal { RANGEv1.Range memory range = RANGE.range(); if (high_) { // Calculate scaleAdjustment for bond market // Price decimals are returned from the perspective of the quote token // so the operations assume payoutPriceDecimal is zero and quotePriceDecimals // is the priceDecimal value int8 priceDecimals = _getPriceDecimals(range.cushion.high.price); int8 scaleAdjustment = int8(ohmDecimals) - int8(reserveDecimals) + (priceDecimals / 2); // Calculate oracle scale and bond scale with scale adjustment and format prices for bond market uint256 oracleScale = 10**uint8(int8(PRICE.decimals()) - priceDecimals); uint256 bondScale = 10 ** uint8( 36 + scaleAdjustment + int8(reserveDecimals) - int8(ohmDecimals) - priceDecimals ); uint256 initialPrice = PRICE.getLastPrice().mulDiv(bondScale, oracleScale); uint256 minimumPrice = range.cushion.high.price.mulDiv(bondScale, oracleScale); // Cache config struct to avoid multiple SLOADs Config memory config_ = _config; // Calculate market capacity from the cushion factor uint256 marketCapacity = range.high.capacity.mulDiv( config_.cushionFactor, ONE_HUNDRED_PERCENT ); // Create new bond market to buy the reserve with OHM IBondSDA.MarketParams memory params = IBondSDA.MarketParams({ payoutToken: ohm, quoteToken: reserve, callbackAddr: address(callback), capacityInQuote: false, capacity: marketCapacity, formattedInitialPrice: initialPrice, formattedMinimumPrice: minimumPrice, debtBuffer: config_.cushionDebtBuffer, vesting: uint48(0), // Instant swaps conclusion: uint48(block.timestamp + config_.cushionDuration), depositInterval: config_.cushionDepositInterval, scaleAdjustment: scaleAdjustment }); uint256 market = auctioneer.createMarket(abi.encode(params)); // Whitelist the bond market on the callback callback.whitelist(address(auctioneer.getTeller()), market); // Update the market information on the range module RANGE.updateMarket(true, market, marketCapacity); } else { // Calculate inverse prices from the oracle feed for the low side uint8 oracleDecimals = PRICE.decimals(); uint256 invCushionPrice = 10**(oracleDecimals * 2) / range.cushion.low.price; uint256 invCurrentPrice = 10**(oracleDecimals * 2) / PRICE.getLastPrice(); // Calculate scaleAdjustment for bond market // Price decimals are returned from the perspective of the quote token // so the operations assume payoutPriceDecimal is zero and quotePriceDecimals // is the priceDecimal value int8 priceDecimals = _getPriceDecimals(invCushionPrice); int8 scaleAdjustment = int8(reserveDecimals) - int8(ohmDecimals) + (priceDecimals / 2); // Calculate oracle scale and bond scale with scale adjustment and format prices for bond market uint256 oracleScale = 10**uint8(int8(oracleDecimals) - priceDecimals); uint256 bondScale = 10 ** uint8( 36 + scaleAdjustment + int8(ohmDecimals) - int8(reserveDecimals) - priceDecimals ); uint256 initialPrice = invCurrentPrice.mulDiv(bondScale, oracleScale); uint256 minimumPrice = invCushionPrice.mulDiv(bondScale, oracleScale); // Cache config struct to avoid multiple SLOADs Config memory config_ = _config; // Calculate market capacity from the cushion factor uint256 marketCapacity = range.low.capacity.mulDiv( config_.cushionFactor, ONE_HUNDRED_PERCENT ); // Create new bond market to buy OHM with the reserve IBondSDA.MarketParams memory params = IBondSDA.MarketParams({ payoutToken: reserve, quoteToken: ohm, callbackAddr: address(callback), capacityInQuote: false, capacity: marketCapacity, formattedInitialPrice: initialPrice, formattedMinimumPrice: minimumPrice, debtBuffer: config_.cushionDebtBuffer, vesting: uint48(0), // Instant swaps conclusion: uint48(block.timestamp + config_.cushionDuration), depositInterval: config_.cushionDepositInterval, scaleAdjustment: scaleAdjustment }); uint256 market = auctioneer.createMarket(abi.encode(params)); // Whitelist the bond market on the callback callback.whitelist(address(auctioneer.getTeller()), market); // Update the market information on the range module RANGE.updateMarket(false, market, marketCapacity); } } /// @notice Deactivate a cushion by closing a bond market (if it is active) /// @param high_ Whether the cushion is for the high or low side of the range (true = high, false = low) function _deactivate(bool high_) internal { uint256 market = RANGE.market(high_); if (auctioneer.isLive(market)) { auctioneer.closeMarket(market); RANGE.updateMarket(high_, type(uint256).max, 0); } } /// @notice Helper function to calculate number of price decimals based on the value returned from the price feed. /// @param price_ The price to calculate the number of decimals for /// @return The number of decimals function _getPriceDecimals(uint256 price_) internal view returns (int8) { int8 decimals; while (price_ >= 10) { price_ = price_ / 10; decimals++; } // Subtract the stated decimals from the calculated decimals to get the relative price decimals. // Required to do it this way vs. normalizing at the beginning since price decimals can be negative. return decimals - int8(PRICE.decimals()); } // ========= INTERNAL FUNCTIONS ========= // /// @notice Update the capacity on the RANGE module. /// @param high_ Whether to update the high side or low side capacity (true = high, false = low). /// @param reduceBy_ The amount to reduce the capacity by (OHM tokens for high side, Reserve tokens for low side). function _updateCapacity(bool high_, uint256 reduceBy_) internal { // Initialize update variables, decrement capacity if a reduceBy amount is provided uint256 capacity = RANGE.capacity(high_) - reduceBy_; // Update capacities on the range module for the wall and market RANGE.updateCapacity(high_, capacity); } /// @notice Update the prices on the RANGE module function _updateRangePrices() internal { // Get latest moving average from the price module uint256 movingAverage = PRICE.getMovingAverage(); // Update the prices on the range module RANGE.updatePrices(movingAverage); } /// @notice Add an observation to the regeneration status variables for each side function _addObservation() internal { // Get latest moving average from the price module uint256 movingAverage = PRICE.getMovingAverage(); // Get price from latest update uint256 currentPrice = PRICE.getLastPrice(); // Store observations and update counts for regeneration // Update low side regen status with a new observation // Observation is positive if the current price is greater than the MA uint32 observe = _config.regenObserve; Regen memory regen = _status.low; if (currentPrice >= movingAverage) { if (!regen.observations[regen.nextObservation]) { _status.low.observations[regen.nextObservation] = true; _status.low.count++; } } else { if (regen.observations[regen.nextObservation]) { _status.low.observations[regen.nextObservation] = false; _status.low.count--; } } _status.low.nextObservation = (regen.nextObservation + 1) % observe; // Update high side regen status with a new observation // Observation is positive if the current price is less than the MA regen = _status.high; if (currentPrice <= movingAverage) { if (!regen.observations[regen.nextObservation]) { _status.high.observations[regen.nextObservation] = true; _status.high.count++; } } else { if (regen.observations[regen.nextObservation]) { _status.high.observations[regen.nextObservation] = false; _status.high.count--; } } _status.high.nextObservation = (regen.nextObservation + 1) % observe; } /// @notice Regenerate the wall for a side /// @param high_ Whether to regenerate the high side or low side (true = high, false = low) function _regenerate(bool high_) internal { // Deactivate cushion if active on the side being regenerated _deactivate(high_); if (high_) { // Reset the regeneration data for the side _status.high.count = uint32(0); _status.high.observations = new bool[](_config.regenObserve); _status.high.nextObservation = uint32(0); _status.high.lastRegen = uint48(block.timestamp); // Calculate capacity uint256 capacity = fullCapacity(true); // Get approval from MINTR to mint OHM up to the capacity // If current approval is higher than the capacity, reduce it uint256 currentApproval = MINTR.mintApproval(address(this)); if (currentApproval < capacity) { MINTR.increaseMintApproval(address(this), capacity - currentApproval); } else if (currentApproval > capacity) { MINTR.decreaseMintApproval(address(this), currentApproval - capacity); } // Regenerate the side with the capacity RANGE.regenerate(true, capacity); } else { // Reset the regeneration data for the side _status.low.count = uint32(0); _status.low.observations = new bool[](_config.regenObserve); _status.low.nextObservation = uint32(0); _status.low.lastRegen = uint48(block.timestamp); // Calculate capacity uint256 capacity = fullCapacity(false); // Get approval from the TRSRY to withdraw up to the capacity in reserves // If current approval is higher than the capacity, reduce it uint256 currentApproval = TRSRY.withdrawApproval(address(this), reserve); if (currentApproval < capacity) { TRSRY.increaseWithdrawApproval(address(this), reserve, capacity - currentApproval); } else if (currentApproval > capacity) { TRSRY.decreaseWithdrawApproval(address(this), reserve, currentApproval - capacity); } // Regenerate the side with the capacity RANGE.regenerate(false, capacity); } } /// @notice Takes down cushions (if active) when a wall is taken down or if available capacity drops below cushion capacity /// @param high_ Whether to check the high side or low side cushion (true = high, false = low) function _checkCushion(bool high_) internal { // Check if the wall is down, if so ensure the cushion is also down // Additionally, if wall is not down, but the wall capacity has dropped below the cushion capacity, take the cushion down bool sideActive = RANGE.active(high_); uint256 market = RANGE.market(high_); if ( !sideActive || (sideActive && auctioneer.isLive(market) && RANGE.capacity(high_) < auctioneer.currentCapacity(market)) ) { _deactivate(high_); } } //============================================================================================// // ADMIN FUNCTIONS // //============================================================================================// /// @inheritdoc IOperator function setSpreads(uint256 cushionSpread_, uint256 wallSpread_) external onlyRole("operator_policy") { // Set spreads on the range module RANGE.setSpreads(cushionSpread_, wallSpread_); // Update range prices (wall and cushion) _updateRangePrices(); } /// @inheritdoc IOperator function setThresholdFactor(uint256 thresholdFactor_) external onlyRole("operator_policy") { // Set threshold factor on the range module RANGE.setThresholdFactor(thresholdFactor_); } /// @inheritdoc IOperator function setCushionFactor(uint32 cushionFactor_) external onlyRole("operator_policy") { // Confirm factor is within allowed values if (cushionFactor_ > ONE_HUNDRED_PERCENT || cushionFactor_ < ONE_PERCENT) revert Operator_InvalidParams(); // Set factor _config.cushionFactor = cushionFactor_; emit CushionFactorChanged(cushionFactor_); } /// @inheritdoc IOperator function setCushionParams( uint32 duration_, uint32 debtBuffer_, uint32 depositInterval_ ) external onlyRole("operator_policy") { // Confirm values are valid if (duration_ > uint256(7 days) || duration_ < uint256(1 days)) revert Operator_InvalidParams(); if (debtBuffer_ < uint32(10_000)) revert Operator_InvalidParams(); if (depositInterval_ < uint32(1 hours) || depositInterval_ > duration_) revert Operator_InvalidParams(); // Update values _config.cushionDuration = duration_; _config.cushionDebtBuffer = debtBuffer_; _config.cushionDepositInterval = depositInterval_; emit CushionParamsChanged(duration_, debtBuffer_, depositInterval_); } /// @inheritdoc IOperator function setReserveFactor(uint32 reserveFactor_) external onlyRole("operator_policy") { // Confirm factor is within allowed values if (reserveFactor_ > ONE_HUNDRED_PERCENT || reserveFactor_ < ONE_PERCENT) revert Operator_InvalidParams(); // Set factor _config.reserveFactor = reserveFactor_; emit ReserveFactorChanged(reserveFactor_); } /// @inheritdoc IOperator function setRegenParams( uint32 wait_, uint32 threshold_, uint32 observe_ ) external onlyRole("operator_policy") { // Confirm regen parameters are within allowed values if ( wait_ < 1 hours || threshold_ > observe_ || observe_ == 0 || threshold_ == 0 || wait_ / PRICE.observationFrequency() < observe_ - threshold_ ) revert Operator_InvalidParams(); // Set regen params _config.regenWait = wait_; _config.regenThreshold = threshold_; _config.regenObserve = observe_; // Re-initialize regen structs with new values (except for last regen) _status.high.count = 0; _status.high.nextObservation = 0; _status.high.observations = new bool[](observe_); _status.low.count = 0; _status.low.nextObservation = 0; _status.low.observations = new bool[](observe_); emit RegenParamsChanged(wait_, threshold_, observe_); } /// @inheritdoc IOperator function setBondContracts(IBondSDA auctioneer_, IBondCallback callback_) external onlyRole("operator_policy") { if (address(auctioneer_) == address(0) || address(callback_) == address(0)) revert Operator_InvalidParams(); // Set contracts auctioneer = auctioneer_; callback = callback_; } /// @inheritdoc IOperator function initialize() external onlyRole("operator_admin") { // Can only call once if (initialized) revert Operator_AlreadyInitialized(); // Update range prices (wall and cushion) _updateRangePrices(); // Regenerate sides _regenerate(true); _regenerate(false); // Set initialized and active flags initialized = true; active = true; } /// @inheritdoc IOperator function regenerate(bool high_) external onlyRole("operator_admin") { // Regenerate side _regenerate(high_); } /// @inheritdoc IOperator function activate() external onlyRole("operator_policy") { active = true; } /// @inheritdoc IOperator function deactivate() external onlyRole("operator_policy") { active = false; // Deactivate cushions _deactivate(true); _deactivate(false); } /// @inheritdoc IOperator function deactivateCushion(bool high_) external onlyRole("operator_policy") { // Manually deactivate a cushion _deactivate(high_); } //============================================================================================// // VIEW FUNCTIONS // //============================================================================================// /// @inheritdoc IOperator function getAmountOut(ERC20 tokenIn_, uint256 amountIn_) public view returns (uint256) { if (tokenIn_ == ohm) { // Calculate amount out uint256 amountOut = amountIn_.mulDiv( 10**reserveDecimals * RANGE.price(true, false), 10**ohmDecimals * 10**PRICE.decimals() ); // Revert if amount out exceeds capacity if (amountOut > RANGE.capacity(false)) revert Operator_InsufficientCapacity(); return amountOut; } else if (tokenIn_ == reserve) { // Calculate amount out uint256 amountOut = amountIn_.mulDiv( 10**ohmDecimals * 10**PRICE.decimals(), 10**reserveDecimals * RANGE.price(true, true) ); // Revert if amount out exceeds capacity if (amountOut > RANGE.capacity(true)) revert Operator_InsufficientCapacity(); return amountOut; } else { revert Operator_InvalidParams(); } } /// @inheritdoc IOperator function fullCapacity(bool high_) public view override returns (uint256) { uint256 reservesInTreasury = TRSRY.getReserveBalance(reserve); uint256 capacity = (reservesInTreasury * _config.reserveFactor) / ONE_HUNDRED_PERCENT; if (high_) { capacity = (capacity.mulDiv( 10**ohmDecimals * 10**PRICE.decimals(), 10**reserveDecimals * RANGE.price(true, true) ) * (ONE_HUNDRED_PERCENT + RANGE.spread(true) * 2)) / ONE_HUNDRED_PERCENT; } return capacity; } /// @inheritdoc IOperator function status() external view override returns (Status memory) { return _status; } /// @inheritdoc IOperator function config() external view override returns (Config memory) { return _config; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Gas optimized reentrancy protection for smart contracts. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) abstract contract ReentrancyGuard { uint256 private locked = 1; modifier nonReentrant() virtual { require(locked == 1, "REENTRANCY"); locked = 2; _; locked = 1; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; // ███████ █████ █████ █████ ██████ ██████ ███████████ █████ █████ █████████ // ███░░░░░███ ░░███ ░░███ ░░███ ░░██████ ██████ ░░███░░░░░███░░███ ░░███ ███░░░░░███ // ███ ░░███ ░███ ░░███ ███ ░███░█████░███ ░███ ░███ ░███ ░███ ░███ ░░░ // ░███ ░███ ░███ ░░█████ ░███░░███ ░███ ░██████████ ░███ ░███ ░░█████████ // ░███ ░███ ░███ ░░███ ░███ ░░░ ░███ ░███░░░░░░ ░███ ░███ ░░░░░░░░███ // ░░███ ███ ░███ █ ░███ ░███ ░███ ░███ ░███ ░███ ███ ░███ // ░░░███████░ ███████████ █████ █████ █████ █████ ░░████████ ░░█████████ // ░░░░░░░ ░░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░ ░░░░░░░░░ //============================================================================================// // GLOBAL TYPES // //============================================================================================// /// @notice Actions to trigger state changes in the kernel. Passed by the executor enum Actions { InstallModule, UpgradeModule, ActivatePolicy, DeactivatePolicy, ChangeExecutor, MigrateKernel } /// @notice Used by executor to select an action and a target contract for a kernel action struct Instruction { Actions action; address target; } /// @notice Used to define which module functions a policy needs access to struct Permissions { Keycode keycode; bytes4 funcSelector; } type Keycode is bytes5; //============================================================================================// // UTIL FUNCTIONS // //============================================================================================// error TargetNotAContract(address target_); error InvalidKeycode(Keycode keycode_); // solhint-disable-next-line func-visibility function toKeycode(bytes5 keycode_) pure returns (Keycode) { return Keycode.wrap(keycode_); } // solhint-disable-next-line func-visibility function fromKeycode(Keycode keycode_) pure returns (bytes5) { return Keycode.unwrap(keycode_); } // solhint-disable-next-line func-visibility function ensureContract(address target_) view { if (target_.code.length == 0) revert TargetNotAContract(target_); } // solhint-disable-next-line func-visibility function ensureValidKeycode(Keycode keycode_) pure { bytes5 unwrapped = Keycode.unwrap(keycode_); for (uint256 i = 0; i < 5; ) { bytes1 char = unwrapped[i]; if (char < 0x41 || char > 0x5A) revert InvalidKeycode(keycode_); // A-Z only unchecked { i++; } } } //============================================================================================// // COMPONENTS // //============================================================================================// /// @notice Generic adapter interface for kernel access in modules and policies. abstract contract KernelAdapter { error KernelAdapter_OnlyKernel(address caller_); Kernel public kernel; constructor(Kernel kernel_) { kernel = kernel_; } /// @notice Modifier to restrict functions to be called only by kernel. modifier onlyKernel() { if (msg.sender != address(kernel)) revert KernelAdapter_OnlyKernel(msg.sender); _; } /// @notice Function used by kernel when migrating to a new kernel. function changeKernel(Kernel newKernel_) external onlyKernel { kernel = newKernel_; } } /// @notice Base level extension of the kernel. Modules act as independent state components to be /// interacted with and mutated through policies. /// @dev Modules are installed and uninstalled via the executor. abstract contract Module is KernelAdapter { error Module_PolicyNotPermitted(address policy_); constructor(Kernel kernel_) KernelAdapter(kernel_) {} /// @notice Modifier to restrict which policies have access to module functions. modifier permissioned() { if (!kernel.modulePermissions(KEYCODE(), Policy(msg.sender), msg.sig)) revert Module_PolicyNotPermitted(msg.sender); _; } /// @notice 5 byte identifier for a module. function KEYCODE() public pure virtual returns (Keycode) {} /// @notice Returns which semantic version of a module is being implemented. /// @return major - Major version upgrade indicates breaking change to the interface. /// @return minor - Minor version change retains backward-compatible interface. function VERSION() external pure virtual returns (uint8 major, uint8 minor) {} /// @notice Initialization function for the module /// @dev This function is called when the module is installed or upgraded by the kernel. /// @dev MUST BE GATED BY onlyKernel. Used to encompass any initialization or upgrade logic. function INIT() external virtual onlyKernel {} } /// @notice Policies are application logic and external interface for the kernel and installed modules. /// @dev Policies are activated and deactivated in the kernel by the executor. /// @dev Module dependencies and function permissions must be defined in appropriate functions. abstract contract Policy is KernelAdapter { error Policy_ModuleDoesNotExist(Keycode keycode_); constructor(Kernel kernel_) KernelAdapter(kernel_) {} /// @notice Easily accessible indicator for if a policy is activated or not. function isActive() external view returns (bool) { return kernel.isPolicyActive(this); } /// @notice Function to grab module address from a given keycode. function getModuleAddress(Keycode keycode_) internal view returns (address) { address moduleForKeycode = address(kernel.getModuleForKeycode(keycode_)); if (moduleForKeycode == address(0)) revert Policy_ModuleDoesNotExist(keycode_); return moduleForKeycode; } /// @notice Define module dependencies for this policy. /// @return dependencies - Keycode array of module dependencies. function configureDependencies() external virtual returns (Keycode[] memory dependencies) {} /// @notice Function called by kernel to set module function permissions. /// @return requests - Array of keycodes and function selectors for requested permissions. function requestPermissions() external view virtual returns (Permissions[] memory requests) {} } /// @notice Main contract that acts as a central component registry for the protocol. /// @dev The kernel manages modules and policies. The kernel is mutated via predefined Actions, /// @dev which are input from any address assigned as the executor. The executor can be changed as needed. contract Kernel { // ========= EVENTS ========= // event PermissionsUpdated( Keycode indexed keycode_, Policy indexed policy_, bytes4 funcSelector_, bool granted_ ); event ActionExecuted(Actions indexed action_, address indexed target_); // ========= ERRORS ========= // error Kernel_OnlyExecutor(address caller_); error Kernel_ModuleAlreadyInstalled(Keycode module_); error Kernel_InvalidModuleUpgrade(Keycode module_); error Kernel_PolicyAlreadyActivated(address policy_); error Kernel_PolicyNotActivated(address policy_); // ========= PRIVILEGED ADDRESSES ========= // /// @notice Address that is able to initiate Actions in the kernel. Can be assigned to a multisig or governance contract. address public executor; // ========= MODULE MANAGEMENT ========= // /// @notice Array of all modules currently installed. Keycode[] public allKeycodes; /// @notice Mapping of module address to keycode. mapping(Keycode => Module) public getModuleForKeycode; /// @notice Mapping of keycode to module address. mapping(Module => Keycode) public getKeycodeForModule; /// @notice Mapping of a keycode to all of its policy dependents. Used to efficiently reconfigure policy dependencies. mapping(Keycode => Policy[]) public moduleDependents; /// @notice Helper for module dependent arrays. Prevents the need to loop through array. mapping(Keycode => mapping(Policy => uint256)) public getDependentIndex; /// @notice Module <> Policy Permissions. /// @dev Keycode -> Policy -> Function Selector -> bool for permission mapping(Keycode => mapping(Policy => mapping(bytes4 => bool))) public modulePermissions; // ========= POLICY MANAGEMENT ========= // /// @notice List of all active policies Policy[] public activePolicies; /// @notice Helper to get active policy quickly. Prevents need to loop through array. mapping(Policy => uint256) public getPolicyIndex; //============================================================================================// // CORE FUNCTIONS // //============================================================================================// constructor() { executor = msg.sender; } /// @notice Modifier to check if caller is the executor. modifier onlyExecutor() { if (msg.sender != executor) revert Kernel_OnlyExecutor(msg.sender); _; } function isPolicyActive(Policy policy_) public view returns (bool) { return activePolicies.length > 0 && activePolicies[getPolicyIndex[policy_]] == policy_; } /// @notice Main kernel function. Initiates state changes to kernel depending on Action passed in. function executeAction(Actions action_, address target_) external onlyExecutor { if (action_ == Actions.InstallModule) { ensureContract(target_); ensureValidKeycode(Module(target_).KEYCODE()); _installModule(Module(target_)); } else if (action_ == Actions.UpgradeModule) { ensureContract(target_); ensureValidKeycode(Module(target_).KEYCODE()); _upgradeModule(Module(target_)); } else if (action_ == Actions.ActivatePolicy) { ensureContract(target_); _activatePolicy(Policy(target_)); } else if (action_ == Actions.DeactivatePolicy) { ensureContract(target_); _deactivatePolicy(Policy(target_)); } else if (action_ == Actions.ChangeExecutor) { executor = target_; } else if (action_ == Actions.MigrateKernel) { ensureContract(target_); _migrateKernel(Kernel(target_)); } emit ActionExecuted(action_, target_); } function _installModule(Module newModule_) internal { Keycode keycode = newModule_.KEYCODE(); if (address(getModuleForKeycode[keycode]) != address(0)) revert Kernel_ModuleAlreadyInstalled(keycode); getModuleForKeycode[keycode] = newModule_; getKeycodeForModule[newModule_] = keycode; allKeycodes.push(keycode); newModule_.INIT(); } function _upgradeModule(Module newModule_) internal { Keycode keycode = newModule_.KEYCODE(); Module oldModule = getModuleForKeycode[keycode]; if (address(oldModule) == address(0) || oldModule == newModule_) revert Kernel_InvalidModuleUpgrade(keycode); getKeycodeForModule[oldModule] = Keycode.wrap(bytes5(0)); getKeycodeForModule[newModule_] = keycode; getModuleForKeycode[keycode] = newModule_; newModule_.INIT(); _reconfigurePolicies(keycode); } function _activatePolicy(Policy policy_) internal { if (isPolicyActive(policy_)) revert Kernel_PolicyAlreadyActivated(address(policy_)); // Add policy to list of active policies activePolicies.push(policy_); getPolicyIndex[policy_] = activePolicies.length - 1; // Record module dependencies Keycode[] memory dependencies = policy_.configureDependencies(); uint256 depLength = dependencies.length; for (uint256 i; i < depLength; ) { Keycode keycode = dependencies[i]; moduleDependents[keycode].push(policy_); getDependentIndex[keycode][policy_] = moduleDependents[keycode].length - 1; unchecked { ++i; } } // Grant permissions for policy to access restricted module functions Permissions[] memory requests = policy_.requestPermissions(); _setPolicyPermissions(policy_, requests, true); } function _deactivatePolicy(Policy policy_) internal { if (!isPolicyActive(policy_)) revert Kernel_PolicyNotActivated(address(policy_)); // Revoke permissions Permissions[] memory requests = policy_.requestPermissions(); _setPolicyPermissions(policy_, requests, false); // Remove policy from all policy data structures uint256 idx = getPolicyIndex[policy_]; Policy lastPolicy = activePolicies[activePolicies.length - 1]; activePolicies[idx] = lastPolicy; activePolicies.pop(); getPolicyIndex[lastPolicy] = idx; delete getPolicyIndex[policy_]; // Remove policy from module dependents _pruneFromDependents(policy_); } /// @notice All functionality will move to the new kernel. WARNING: ACTION WILL BRICK THIS KERNEL. /// @dev New kernel must add in all of the modules and policies via executeAction. /// @dev NOTE: Data does not get cleared from this kernel. function _migrateKernel(Kernel newKernel_) internal { uint256 keycodeLen = allKeycodes.length; for (uint256 i; i < keycodeLen; ) { Module module = Module(getModuleForKeycode[allKeycodes[i]]); module.changeKernel(newKernel_); unchecked { ++i; } } uint256 policiesLen = activePolicies.length; for (uint256 j; j < policiesLen; ) { Policy policy = activePolicies[j]; // Deactivate before changing kernel policy.changeKernel(newKernel_); unchecked { ++j; } } } function _reconfigurePolicies(Keycode keycode_) internal { Policy[] memory dependents = moduleDependents[keycode_]; uint256 depLength = dependents.length; for (uint256 i; i < depLength; ) { dependents[i].configureDependencies(); unchecked { ++i; } } } function _setPolicyPermissions( Policy policy_, Permissions[] memory requests_, bool grant_ ) internal { uint256 reqLength = requests_.length; for (uint256 i = 0; i < reqLength; ) { Permissions memory request = requests_[i]; modulePermissions[request.keycode][policy_][request.funcSelector] = grant_; emit PermissionsUpdated(request.keycode, policy_, request.funcSelector, grant_); unchecked { ++i; } } } function _pruneFromDependents(Policy policy_) internal { Keycode[] memory dependencies = policy_.configureDependencies(); uint256 depcLength = dependencies.length; for (uint256 i; i < depcLength; ) { Keycode keycode = dependencies[i]; Policy[] storage dependents = moduleDependents[keycode]; uint256 origIndex = getDependentIndex[keycode][policy_]; Policy lastPolicy = dependents[dependents.length - 1]; // Swap with last and pop dependents[origIndex] = lastPolicy; dependents.pop(); // Record new index and delete deactivated policy index getDependentIndex[keycode][lastPolicy] = origIndex; delete getDependentIndex[keycode][policy_]; unchecked { ++i; } } } }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity >=0.7.5; /// @notice Olympus OHM token /// @dev This contract is the legacy v2 OHM token. Included in the repo for completeness, /// since it is not being changed and is imported in some contracts. interface IOlympusAuthority { // ========= EVENTS ========= // event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately); event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately); event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately); event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately); event GovernorPulled(address indexed from, address indexed to); event GuardianPulled(address indexed from, address indexed to); event PolicyPulled(address indexed from, address indexed to); event VaultPulled(address indexed from, address indexed to); // ========= VIEW ========= // function governor() external view returns (address); function guardian() external view returns (address); function policy() external view returns (address); function vault() external view returns (address); } // File: types/OlympusAccessControlled.sol abstract contract OlympusAccessControlled { // ========= EVENTS ========= // event AuthorityUpdated(IOlympusAuthority indexed authority); string internal UNAUTHORIZED = "UNAUTHORIZED"; // save gas // ========= STATE VARIABLES ========= // IOlympusAuthority public authority; // ========= Constructor ========= // constructor(IOlympusAuthority _authority) { authority = _authority; emit AuthorityUpdated(_authority); } // ========= MODIFIERS ========= // modifier onlyGovernor() { require(msg.sender == authority.governor(), UNAUTHORIZED); _; } modifier onlyGuardian() { require(msg.sender == authority.guardian(), UNAUTHORIZED); _; } modifier onlyPermitted() { require(msg.sender == authority.policy(), UNAUTHORIZED); _; } modifier onlyVault() { require(msg.sender == authority.vault(), UNAUTHORIZED); _; } // ========= GOV ONLY ========= // function setAuthority(IOlympusAuthority _newAuthority) external onlyGovernor { authority = _newAuthority; emit AuthorityUpdated(_newAuthority); } } // File: cryptography/ECDSA.sol /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } } // File: cryptography/EIP712.sol /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { uint256 chainID; assembly { chainID := chainid() } bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = chainID; _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { uint256 chainID; assembly { chainID := chainid() } if (chainID == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { uint256 chainID; assembly { chainID := chainid() } return keccak256(abi.encode(typeHash, nameHash, versionHash, chainID, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } } // File: interfaces/IERC20Permit.sol /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as th xe allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); } // File: interfaces/IERC20.sol interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: interfaces/IOHM.sol interface IOHM is IERC20 { function mint(address account_, uint256 amount_) external; function burn(uint256 amount) external; function burnFrom(address account_, uint256 amount_) external; } // File: libraries/SafeMath.sol library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; assert(a == b * c + (a % b)); // There is no case in which this doesn't hold return c; } // Only used in the BondingCalculator.sol function sqrrt(uint256 a) internal pure returns (uint256 c) { if (a > 3) { c = a; uint256 b = add(div(a, 2), 1); while (b < c) { c = b; b = div(add(div(a, b), b), 2); } } else if (a != 0) { c = 1; } } } // File: libraries/Counters.sol library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // File: types/ERC20.sol abstract contract ERC20 is IERC20 { using SafeMath for uint256; // TODO comment actual hash value. bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID = keccak256("ERC20Token"); mapping(address => uint256) internal _balances; mapping(address => mapping(address => uint256)) internal _allowances; uint256 internal _totalSupply; string internal _name; string internal _symbol; uint8 internal immutable _decimals; constructor( string memory name_, string memory symbol_, uint8 decimals_ ) { _name = name_; _symbol = symbol_; _decimals = decimals_; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view virtual returns (uint8) { return _decimals; } function totalSupply() public view override returns (uint256) { return _totalSupply; } function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(msg.sender, recipient, amount); return true; } function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(msg.sender, spender, amount); return true; } function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve( sender, msg.sender, _allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance") ); return true; } function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve( msg.sender, spender, _allowances[msg.sender][spender].sub( subtractedValue, "ERC20: decreased allowance below zero" ) ); return true; } function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _beforeTokenTransfer( address from_, address to_, uint256 amount_ ) internal virtual {} } // File: types/ERC20Permit.sol /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private immutable _PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) EIP712(name, "1") {} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256( abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { Counters.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } } // File: OlympusERC20.sol contract OlympusERC20Token is ERC20Permit, IOHM, OlympusAccessControlled { using SafeMath for uint256; constructor(address _authority) ERC20("Olympus", "OHM", 9) ERC20Permit("Olympus") OlympusAccessControlled(IOlympusAuthority(_authority)) {} function mint(address account_, uint256 amount_) external override onlyVault { _mint(account_, amount_); } function burn(uint256 amount) external override { _burn(msg.sender, amount); } function burnFrom(address account_, uint256 amount_) external override { _burnFrom(account_, amount_); } function _burnFrom(address account_, uint256 amount_) internal { uint256 decreasedAllowance_ = allowance(account_, msg.sender).sub( amount_, "ERC20: burn amount exceeds allowance" ); _approve(account_, msg.sender, decreasedAllowance_); _burn(account_, amount_); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorInterface { function latestAnswer() external view returns (int256); function latestTimestamp() external view returns (uint256); function latestRound() external view returns (uint256); function getAnswer(uint256 roundId) external view returns (int256); function getTimestamp(uint256 roundId) external view returns (uint256); event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); } interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IBondAuctioneer} from "../interfaces/IBondAuctioneer.sol"; import {IBondTeller} from "../interfaces/IBondTeller.sol"; interface IBondAggregator { /// @notice Register a auctioneer with the aggregator /// @notice Only Guardian /// @param auctioneer_ Address of the Auctioneer to register /// @dev A auctioneer must be registered with an aggregator to create markets function registerAuctioneer(IBondAuctioneer auctioneer_) external; /// @notice Register a new market with the aggregator /// @notice Only registered depositories /// @param payoutToken_ Token to be paid out by the market /// @param quoteToken_ Token to be accepted by the market /// @param marketId ID of the market being created function registerMarket(ERC20 payoutToken_, ERC20 quoteToken_) external returns (uint256 marketId); /// @notice Get the auctioneer for the provided market ID /// @param id_ ID of Market function getAuctioneer(uint256 id_) external view returns (IBondAuctioneer); /// @notice Calculate current market price of payout token in quote tokens /// @dev Accounts for debt and control variable decay since last deposit (vs _marketPrice()) /// @param id_ ID of market /// @return Price for market (see the specific auctioneer for units) // // if price is below minimum price, minimum price is returned // this is enforced on deposits by manipulating total debt (see _decay()) function marketPrice(uint256 id_) external view returns (uint256); /// @notice Scale value to use when converting between quote token and payout token amounts with marketPrice() /// @param id_ ID of market /// @return Scaling factor for market in configured decimals function marketScale(uint256 id_) external view returns (uint256); /// @notice Payout due for amount of quote tokens /// @dev Accounts for debt and control variable decay so it is up to date /// @param amount_ Amount of quote tokens to spend /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. /// @return amount of payout tokens to be paid function payoutFor( uint256 amount_, uint256 id_, address referrer_ ) external view returns (uint256); /// @notice Returns maximum amount of quote token accepted by the market /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. function maxAmountAccepted(uint256 id_, address referrer_) external view returns (uint256); /// @notice Does market send payout immediately /// @param id_ Market ID to search for function isInstantSwap(uint256 id_) external view returns (bool); /// @notice Is a given market accepting deposits /// @param id_ ID of market function isLive(uint256 id_) external view returns (bool); /// @notice Returns array of active market IDs within a range /// @dev Should be used if length exceeds max to query entire array function liveMarketsBetween(uint256 firstIndex_, uint256 lastIndex_) external view returns (uint256[] memory); /// @notice Returns an array of all active market IDs for a given quote token /// @param token_ Address of token to query by /// @param isPayout_ If true, search by payout token, else search for quote token function liveMarketsFor(address token_, bool isPayout_) external view returns (uint256[] memory); /// @notice Returns an array of all active market IDs for a given owner /// @param owner_ Address of owner to query by /// @param firstIndex_ Market ID to start at /// @param lastIndex_ Market ID to end at (non-inclusive) function liveMarketsBy( address owner_, uint256 firstIndex_, uint256 lastIndex_ ) external view returns (uint256[] memory); /// @notice Returns an array of all active market IDs for a given payout and quote token /// @param payout_ Address of payout token /// @param quote_ Address of quote token function marketsFor(address payout_, address quote_) external view returns (uint256[] memory); /// @notice Returns the market ID with the highest current payoutToken payout for depositing quoteToken /// @param payout_ Address of payout token /// @param quote_ Address of quote token /// @param amountIn_ Amount of quote tokens to deposit /// @param minAmountOut_ Minimum amount of payout tokens to receive as payout /// @param maxExpiry_ Latest acceptable vesting timestamp for bond /// Inputting the zero address will take into account just the protocol fee. function findMarketFor( address payout_, address quote_, uint256 amountIn_, uint256 minAmountOut_, uint256 maxExpiry_ ) external view returns (uint256 id); /// @notice Returns the Teller that services the market ID function getTeller(uint256 id_) external view returns (IBondTeller); /// @notice Returns current capacity of a market function currentCapacity(uint256 id_) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IBondTeller} from "../interfaces/IBondTeller.sol"; import {IBondAggregator} from "../interfaces/IBondAggregator.sol"; interface IBondAuctioneer { /// @notice Creates a new bond market /// @param params_ Configuration data needed for market creation, encoded in a bytes array /// @dev See specific auctioneer implementations for details on encoding the parameters. /// @return id ID of new bond market function createMarket(bytes memory params_) external returns (uint256); /// @notice Disable existing bond market /// @notice Must be market owner /// @param id_ ID of market to close function closeMarket(uint256 id_) external; /// @notice Exchange quote tokens for a bond in a specified market /// @notice Must be teller /// @param id_ ID of the Market the bond is being purchased from /// @param amount_ Amount to deposit in exchange for bond (after fee has been deducted) /// @param minAmountOut_ Minimum acceptable amount of bond to receive. Prevents frontrunning /// @return payout Amount of payout token to be received from the bond function purchaseBond( uint256 id_, uint256 amount_, uint256 minAmountOut_ ) external returns (uint256 payout); /// @notice Set market intervals to different values than the defaults /// @notice Must be market owner /// @dev Changing the intervals could cause markets to behave in unexpected way /// tuneInterval should be greater than tuneAdjustmentDelay /// @param id_ Market ID /// @param intervals_ Array of intervals (3) /// 1. Tune interval - Frequency of tuning /// 2. Tune adjustment delay - Time to implement downward tuning adjustments /// 3. Debt decay interval - Interval over which debt should decay completely function setIntervals(uint256 id_, uint32[3] calldata intervals_) external; /// @notice Designate a new owner of a market /// @notice Must be market owner /// @dev Doesn't change permissions until newOwner calls pullOwnership /// @param id_ Market ID /// @param newOwner_ New address to give ownership to function pushOwnership(uint256 id_, address newOwner_) external; /// @notice Accept ownership of a market /// @notice Must be market newOwner /// @dev The existing owner must call pushOwnership prior to the newOwner calling this function /// @param id_ Market ID function pullOwnership(uint256 id_) external; /// @notice Set the auctioneer defaults /// @notice Must be policy /// @param defaults_ Array of default values /// 1. Tune interval - amount of time between tuning adjustments /// 2. Tune adjustment delay - amount of time to apply downward tuning adjustments /// 3. Minimum debt decay interval - minimum amount of time to let debt decay to zero /// 4. Minimum deposit interval - minimum amount of time to wait between deposits /// 5. Minimum market duration - minimum amount of time a market can be created for /// 6. Minimum debt buffer - the minimum amount of debt over the initial debt to trigger a market shutdown /// @dev The defaults set here are important to avoid edge cases in market behavior, e.g. a very short market reacts doesn't tune well /// @dev Only applies to new markets that are created after the change function setDefaults(uint32[6] memory defaults_) external; /// @notice Change the status of the auctioneer to allow creation of new markets /// @dev Setting to false and allowing active markets to end will sunset the auctioneer /// @param status_ Allow market creation (true) : Disallow market creation (false) function setAllowNewMarkets(bool status_) external; /// @notice Change whether a market creator is allowed to use a callback address in their markets or not /// @notice Must be guardian /// @dev Callback is believed to be safe, but a whitelist is implemented to prevent abuse /// @param creator_ Address of market creator /// @param status_ Allow callback (true) : Disallow callback (false) function setCallbackAuthStatus(address creator_, bool status_) external; /* ========== VIEW FUNCTIONS ========== */ /// @notice Provides information for the Teller to execute purchases on a Market /// @param id_ Market ID /// @return owner Address of the market owner (tokens transferred from this address if no callback) /// @return callbackAddr Address of the callback contract to get tokens for payouts /// @return payoutToken Payout Token (token paid out) for the Market /// @return quoteToken Quote Token (token received) for the Market /// @return vesting Timestamp or duration for vesting, implementation-dependent /// @return maxPayout Maximum amount of payout tokens you can purchase in one transaction function getMarketInfoForPurchase(uint256 id_) external view returns ( address owner, address callbackAddr, ERC20 payoutToken, ERC20 quoteToken, uint48 vesting, uint256 maxPayout ); /// @notice Calculate current market price of payout token in quote tokens /// @param id_ ID of market /// @return Price for market in configured decimals // // if price is below minimum price, minimum price is returned function marketPrice(uint256 id_) external view returns (uint256); /// @notice Scale value to use when converting between quote token and payout token amounts with marketPrice() /// @param id_ ID of market /// @return Scaling factor for market in configured decimals function marketScale(uint256 id_) external view returns (uint256); /// @notice Payout due for amount of quote tokens /// @dev Accounts for debt and control variable decay so it is up to date /// @param amount_ Amount of quote tokens to spend /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. /// @return amount of payout tokens to be paid function payoutFor( uint256 amount_, uint256 id_, address referrer_ ) external view returns (uint256); /// @notice Returns maximum amount of quote token accepted by the market /// @param id_ ID of market /// @param referrer_ Address of referrer, used to get fees to calculate accurate payout amount. /// Inputting the zero address will take into account just the protocol fee. function maxAmountAccepted(uint256 id_, address referrer_) external view returns (uint256); /// @notice Does market send payout immediately /// @param id_ Market ID to search for function isInstantSwap(uint256 id_) external view returns (bool); /// @notice Is a given market accepting deposits /// @param id_ ID of market function isLive(uint256 id_) external view returns (bool); /// @notice Returns the address of the market owner /// @param id_ ID of market function ownerOf(uint256 id_) external view returns (address); /// @notice Returns the Teller that services the Auctioneer function getTeller() external view returns (IBondTeller); /// @notice Returns the Aggregator that services the Auctioneer function getAggregator() external view returns (IBondAggregator); /// @notice Returns current capacity of a market function currentCapacity(uint256 id_) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; interface IBondCallback { /// @notice Send payout tokens to Teller while allowing market owners to perform custom logic on received or paid out tokens /// @notice Market ID on Teller must be whitelisted /// @param id_ ID of the market /// @param inputAmount_ Amount of quote tokens bonded to the market /// @param outputAmount_ Amount of payout tokens to be paid out to the market /// @dev Must transfer the output amount of payout tokens back to the Teller /// @dev Should check that the quote tokens have been transferred to the contract in the _callback function function callback( uint256 id_, uint256 inputAmount_, uint256 outputAmount_ ) external; /// @notice Returns the number of quote tokens received and payout tokens paid out for a market /// @param id_ ID of the market /// @return in_ Amount of quote tokens bonded to the market /// @return out_ Amount of payout tokens paid out to the market function amountsForMarket(uint256 id_) external view returns (uint256 in_, uint256 out_); /// @notice Whitelist a teller and market ID combination /// @notice Must be callback owner /// @param teller_ Address of the Teller contract which serves the market /// @param id_ ID of the market function whitelist(address teller_, uint256 id_) external; /// @notice Remove a market ID on a teller from the whitelist /// @dev Shutdown function in case there's an issue with the teller /// @param teller_ Address of the Teller contract which serves the market /// @param id_ ID of the market to remove from whitelist function blacklist(address teller_, uint256 id_) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IBondAuctioneer} from "../interfaces/IBondAuctioneer.sol"; interface IBondSDA is IBondAuctioneer { /// @notice Main information pertaining to bond market struct BondMarket { address owner; // market owner. sends payout tokens, receives quote tokens (defaults to creator) ERC20 payoutToken; // token to pay depositors with ERC20 quoteToken; // token to accept as payment address callbackAddr; // address to call for any operations on bond purchase. Must inherit to IBondCallback. bool capacityInQuote; // capacity limit is in payment token (true) or in payout (false, default) uint256 capacity; // capacity remaining uint256 totalDebt; // total payout token debt from market uint256 minPrice; // minimum price (hard floor for the market) uint256 maxPayout; // max payout tokens out in one order uint256 sold; // payout tokens out uint256 purchased; // quote tokens in uint256 scale; // scaling factor for the market (see MarketParams struct) } /// @notice Information used to control how a bond market changes struct BondTerms { uint256 controlVariable; // scaling variable for price uint256 maxDebt; // max payout token debt accrued uint48 vesting; // length of time from deposit to expiry if fixed-term, vesting timestamp if fixed-expiry uint48 conclusion; // timestamp when market no longer offered } /// @notice Data needed for tuning bond market /// @dev Durations are stored in uint32 (not int32) and timestamps are stored in uint48, so is not subject to Y2K38 overflow struct BondMetadata { uint48 lastTune; // last timestamp when control variable was tuned uint48 lastDecay; // last timestamp when market was created and debt was decayed uint32 length; // time from creation to conclusion. uint32 depositInterval; // target frequency of deposits uint32 tuneInterval; // frequency of tuning uint32 tuneAdjustmentDelay; // time to implement downward tuning adjustments uint32 debtDecayInterval; // interval over which debt should decay completely uint256 tuneIntervalCapacity; // capacity expected to be used during a tuning interval uint256 tuneBelowCapacity; // capacity that the next tuning will occur at uint256 lastTuneDebt; // target debt calculated at last tuning } /// @notice Control variable adjustment data struct Adjustment { uint256 change; uint48 lastAdjustment; uint48 timeToAdjusted; // how long until adjustment happens bool active; } /// @notice Parameters to create a new bond market /// @dev Note price should be passed in a specific format: /// formatted price = (payoutPriceCoefficient / quotePriceCoefficient) /// * 10**(36 + scaleAdjustment + quoteDecimals - payoutDecimals + payoutPriceDecimals - quotePriceDecimals) /// where: /// payoutDecimals - Number of decimals defined for the payoutToken in its ERC20 contract /// quoteDecimals - Number of decimals defined for the quoteToken in its ERC20 contract /// payoutPriceCoefficient - The coefficient of the payoutToken price in scientific notation (also known as the significant digits) /// payoutPriceDecimals - The significand of the payoutToken price in scientific notation (also known as the base ten exponent) /// quotePriceCoefficient - The coefficient of the quoteToken price in scientific notation (also known as the significant digits) /// quotePriceDecimals - The significand of the quoteToken price in scientific notation (also known as the base ten exponent) /// scaleAdjustment - see below /// * In the above definitions, the "prices" need to have the same unit of account (i.e. both in OHM, $, ETH, etc.) /// If price is not provided in this format, the market will not behave as intended. /// @param params_ Encoded bytes array, with the following elements /// @dev 0. Payout Token (token paid out) /// @dev 1. Quote Token (token to be received) /// @dev 2. Callback contract address, should conform to IBondCallback. If 0x00, tokens will be transferred from market.owner /// @dev 3. Is Capacity in Quote Token? /// @dev 4. Capacity (amount in quoteDecimals or amount in payoutDecimals) /// @dev 5. Formatted initial price (see note above) /// @dev 6. Formatted minimum price (see note above) /// @dev 7. Debt buffer. Percent with 3 decimals. Percentage over the initial debt to allow the market to accumulate at anyone time. /// @dev Works as a circuit breaker for the market in case external conditions incentivize massive buying (e.g. stablecoin depeg). /// @dev Minimum is the greater of 10% or initial max payout as a percentage of capacity. /// @dev If the value is too small, the market will not be able function normally and close prematurely. /// @dev If the value is too large, the market will not circuit break when intended. The value must be > 10% but can exceed 100% if desired. /// @dev A good heuristic to calculate a debtBuffer with is to determine the amount of capacity that you think is reasonable to be expended /// @dev in a short duration as a percent, e.g. 25%. Then a reasonable debtBuffer would be: 0.25 * 1e3 * decayInterval / marketDuration /// @dev where decayInterval = max(3 days, 5 * depositInterval) and marketDuration = conclusion - creation time. /// @dev 8. Is fixed term ? Vesting length (seconds) : Vesting expiry (timestamp). /// @dev A 'vesting' param longer than 50 years is considered a timestamp for fixed expiry. /// @dev 9. Conclusion (timestamp) /// @dev 10. Deposit interval (seconds) /// @dev 11. Market scaling factor adjustment, ranges from -24 to +24 within the configured market bounds. /// @dev Should be calculated as: (payoutDecimals - quoteDecimals) - ((payoutPriceDecimals - quotePriceDecimals) / 2) /// @dev Providing a scaling factor adjustment that doesn't follow this formula could lead to under or overflow errors in the market. /// @return ID of new bond market struct MarketParams { ERC20 payoutToken; ERC20 quoteToken; address callbackAddr; bool capacityInQuote; uint256 capacity; uint256 formattedInitialPrice; uint256 formattedMinimumPrice; uint32 debtBuffer; uint48 vesting; uint48 conclusion; uint32 depositInterval; int8 scaleAdjustment; } /* ========== VIEW FUNCTIONS ========== */ /// @notice Calculate current market price of payout token in quote tokens /// @dev Accounts for debt and control variable decay since last deposit (vs _marketPrice()) /// @param id_ ID of market /// @return Price for market in configured decimals (see MarketParams) // // price is derived from the equation // // p = c * d // // where // p = price // c = control variable // d = debt // // d -= ( d * (dt / l) ) // // where // dt = change in time // l = length of program // // if price is below minimum price, minimum price is returned // this is enforced on deposits by manipulating total debt (see _decay()) function marketPrice(uint256 id_) external view override returns (uint256); /// @notice Calculate debt factoring in decay /// @dev Accounts for debt decay since last deposit /// @param id_ ID of market /// @return Current debt for market in payout token decimals function currentDebt(uint256 id_) external view returns (uint256); /// @notice Up to date control variable /// @dev Accounts for control variable adjustment /// @param id_ ID of market /// @return Control variable for market in payout token decimals function currentControlVariable(uint256 id_) external view returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; interface IBondTeller { /// @notice Exchange quote tokens for a bond in a specified market /// @param recipient_ Address of recipient of bond. Allows deposits for other addresses /// @param referrer_ Address of referrer who will receive referral fee. For frontends to fill. /// Direct calls can use the zero address for no referrer fee. /// @param id_ ID of the Market the bond is being purchased from /// @param amount_ Amount to deposit in exchange for bond /// @param minAmountOut_ Minimum acceptable amount of bond to receive. Prevents frontrunning /// @return Amount of payout token to be received from the bond /// @return Timestamp at which the bond token can be redeemed for the underlying token function purchase( address recipient_, address referrer_, uint256 id_, uint256 amount_, uint256 minAmountOut_ ) external returns (uint256, uint48); /// @notice Get current fee charged by the teller based on the combined protocol and referrer fee /// @param referrer_ Address of the referrer /// @return Fee in basis points (3 decimal places) function getFee(address referrer_) external view returns (uint48); /// @notice Set protocol fee /// @notice Must be guardian /// @param fee_ Protocol fee in basis points (3 decimal places) function setProtocolFee(uint48 fee_) external; /// @notice Set the discount for creating bond tokens from the base protocol fee /// @dev The discount is subtracted from the protocol fee to determine the fee /// when using create() to mint bond tokens without using an Auctioneer /// @param discount_ Create Fee Discount in basis points (3 decimal places) function setCreateFeeDiscount(uint48 discount_) external; /// @notice Set your fee as a referrer to the protocol /// @notice Fee is set for sending address /// @param fee_ Referrer fee in basis points (3 decimal places) function setReferrerFee(uint48 fee_) external; /// @notice Claim fees accrued by sender in the input tokens and sends them to the provided address /// @param tokens_ Array of tokens to claim fees for /// @param to_ Address to send fees to function claimFees(ERC20[] memory tokens_, address to_) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. uint256 twos = (type(uint256).max - denominator + 1) & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { result = mulDiv(a, b, denominator); unchecked { if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; /// @notice Safe ERC20 and ETH transfer library that safely handles missing return values. /// @author Modified from Uniswap & old Solmate (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/TransferHelper.sol) library TransferHelper { function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(ERC20.transferFrom.selector, from, to, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(ERC20.transfer.selector, to, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(ERC20.approve.selector, to, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED"); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import {OlympusERC20Token as OHM} from "src/external/OlympusERC20.sol"; import "src/Kernel.sol"; /// @notice Wrapper for minting and burning functions of OHM token. abstract contract MINTRv1 is Module { // ========= EVENTS ========= // event IncreaseMintApproval(address indexed policy_, uint256 newAmount_); event DecreaseMintApproval(address indexed policy_, uint256 newAmount_); event Mint(address indexed policy_, address indexed to_, uint256 amount_); event Burn(address indexed policy_, address indexed from_, uint256 amount_); // ========= ERRORS ========= // error MINTR_NotApproved(); error MINTR_ZeroAmount(); error MINTR_NotActive(); // ========= STATE ========= // OHM public ohm; /// @notice Status of the minter. If false, minting and burning OHM is disabled. bool public active; /// @notice Mapping of who is approved for minting. /// @dev minter -> amount. Infinite approval is max(uint256). mapping(address => uint256) public mintApproval; // ========= FUNCTIONS ========= // modifier onlyWhileActive() { if (!active) revert MINTR_NotActive(); _; } /// @notice Mint OHM to an address. function mintOhm(address to_, uint256 amount_) external virtual; /// @notice Burn OHM from an address. Must have approval. function burnOhm(address from_, uint256 amount_) external virtual; /// @notice Increase approval for specific withdrawer addresses /// @dev Policies must explicity request how much they want approved before withdrawing. function increaseMintApproval(address policy_, uint256 amount_) external virtual; /// @notice Decrease approval for specific withdrawer addresses function decreaseMintApproval(address policy_, uint256 amount_) external virtual; /// @notice Emergency shutdown of minting and burning. function deactivate() external virtual; /// @notice Re-activate minting and burning after shutdown. function activate() external virtual; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.15; import {AggregatorV2V3Interface} from "interfaces/AggregatorV2V3Interface.sol"; import "src/Kernel.sol"; /// @notice Price oracle data storage /// @dev The Olympus Price Oracle contract provides a standard interface for OHM price data against a reserve asset. /// It also implements a moving average price calculation (same as a TWAP) on the price feed data over a configured /// duration and observation frequency. The data provided by this contract is used by the Olympus Range Operator to /// perform market operations. The Olympus Price Oracle is updated each epoch by the Olympus Heart contract. abstract contract PRICEv1 is Module { // ========= EVENTS ========= // event NewObservation(uint256 timestamp_, uint256 price_, uint256 movingAverage_); event MovingAverageDurationChanged(uint48 movingAverageDuration_); event ObservationFrequencyChanged(uint48 observationFrequency_); event UpdateThresholdsChanged(uint48 ohmEthUpdateThreshold_, uint48 reserveEthUpdateThreshold_); // ========= ERRORS ========= // error Price_InvalidParams(); error Price_NotInitialized(); error Price_AlreadyInitialized(); error Price_BadFeed(address priceFeed); // ========= STATE ========= // /// @dev Price feeds. Chainlink typically provides price feeds for an asset in ETH. Therefore, we use two price feeds against ETH, one for OHM and one for the Reserve asset, to calculate the relative price of OHM in the Reserve asset. /// @dev Update thresholds are the maximum amount of time that can pass between price feed updates before the price oracle is considered stale. These should be set based on the parameters of the price feed. /// @notice OHM/ETH price feed AggregatorV2V3Interface public ohmEthPriceFeed; /// @notice Maximum expected time between OHM/ETH price feed updates uint48 public ohmEthUpdateThreshold; /// @notice Reserve/ETH price feed AggregatorV2V3Interface public reserveEthPriceFeed; /// @notice Maximum expected time between OHM/ETH price feed updates uint48 public reserveEthUpdateThreshold; /// @notice Running sum of observations to calculate the moving average price from /// @dev See getMovingAverage() uint256 public cumulativeObs; /// @notice Array of price observations. Check nextObsIndex to determine latest data point. /// @dev Observations are stored in a ring buffer where the moving average is the sum of all observations divided by the number of observations. /// Observations can be cleared by changing the movingAverageDuration or observationFrequency and must be re-initialized. uint256[] public observations; /// @notice Index of the next observation to make. The current value at this index is the oldest observation. uint32 public nextObsIndex; /// @notice Number of observations used in the moving average calculation. Computed from movingAverageDuration / observationFrequency. uint32 public numObservations; /// @notice Frequency (in seconds) that observations should be stored. uint48 public observationFrequency; /// @notice Duration (in seconds) over which the moving average is calculated. uint48 public movingAverageDuration; /// @notice Unix timestamp of last observation (in seconds). uint48 public lastObservationTime; /// @notice Whether the price module is initialized (and therefore active). bool public initialized; /// @notice Number of decimals in the price values provided by the contract. uint8 public constant decimals = 18; // ========= FUNCTIONS ========= // /// @notice Trigger an update of the moving average. Permissioned. /// @dev This function does not have a time-gating on the observationFrequency on this contract. It is set on the Heart policy contract. /// The Heart beat frequency should be set to the same value as the observationFrequency. function updateMovingAverage() external virtual; /// @notice Initialize the price module /// @notice Access restricted to activated policies /// @param startObservations_ - Array of observations to initialize the moving average with. Must be of length numObservations. /// @param lastObservationTime_ - Unix timestamp of last observation being provided (in seconds). /// @dev This function must be called after the Price module is deployed to activate it and after updating the observationFrequency /// or movingAverageDuration (in certain cases) in order for the Price module to function properly. function initialize(uint256[] memory startObservations_, uint48 lastObservationTime_) external virtual; /// @notice Change the moving average window (duration) /// @param movingAverageDuration_ - Moving average duration in seconds, must be a multiple of observation frequency /// @dev Changing the moving average duration will erase the current observations array /// and require the initialize function to be called again. Ensure that you have saved /// the existing data and can re-populate before calling this function. function changeMovingAverageDuration(uint48 movingAverageDuration_) external virtual; /// @notice Change the observation frequency of the moving average (i.e. how often a new observation is taken) /// @param observationFrequency_ - Observation frequency in seconds, must be a divisor of the moving average duration /// @dev Changing the observation frequency clears existing observation data since it will not be taken at the right time intervals. /// Ensure that you have saved the existing data and/or can re-populate before calling this function. function changeObservationFrequency(uint48 observationFrequency_) external virtual; /// @notice Change the update thresholds for the price feeds /// @param ohmEthUpdateThreshold_ - Maximum allowed time between OHM/ETH price feed updates /// @param reserveEthUpdateThreshold_ - Maximum allowed time between Reserve/ETH price feed updates /// @dev The update thresholds should be set based on the update threshold of the chainlink oracles. function changeUpdateThresholds( uint48 ohmEthUpdateThreshold_, uint48 reserveEthUpdateThreshold_ ) external virtual; /// @notice Get the current price of OHM in the Reserve asset from the price feeds function getCurrentPrice() external view virtual returns (uint256); /// @notice Get the last stored price observation of OHM in the Reserve asset function getLastPrice() external view virtual returns (uint256); /// @notice Get the moving average of OHM in the Reserve asset over the defined window (see movingAverageDuration and observationFrequency). function getMovingAverage() external view virtual returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.15; import {ERC20} from "solmate/tokens/ERC20.sol"; import "src/Kernel.sol"; abstract contract RANGEv1 is Module { // ========= EVENTS ========= // event WallUp(bool high_, uint256 timestamp_, uint256 capacity_); event WallDown(bool high_, uint256 timestamp_, uint256 capacity_); event CushionUp(bool high_, uint256 timestamp_, uint256 capacity_); event CushionDown(bool high_, uint256 timestamp_); event PricesChanged( uint256 wallLowPrice_, uint256 cushionLowPrice_, uint256 cushionHighPrice_, uint256 wallHighPrice_ ); event SpreadsChanged(uint256 cushionSpread_, uint256 wallSpread_); event ThresholdFactorChanged(uint256 thresholdFactor_); // ========= ERRORS ========= // error RANGE_InvalidParams(); // ========= STATE ========= // struct Line { uint256 price; // Price for the specified level } struct Band { Line high; // Price of the high side of the band Line low; // Price of the low side of the band uint256 spread; // Spread of the band (increase/decrease from the moving average to set the band prices), percent with 2 decimal places (i.e. 1000 = 10% spread) } struct Side { bool active; // Whether or not the side is active (i.e. the Operator is performing market operations on this side, true = active, false = inactive) uint48 lastActive; // Unix timestamp when the side was last active (in seconds) uint256 capacity; // Amount of tokens that can be used to defend the side of the range. Specified in OHM tokens on the high side and Reserve tokens on the low side. uint256 threshold; // Minimum number of tokens required in capacity to maintain an active side. Specified in OHM tokens on the high side and Reserve tokens on the low side. uint256 market; // Market ID of the cushion bond market for the side. If no market is active, the market ID is set to max uint256 value. } struct Range { Side low; // Data specific to the low side of the range Side high; // Data specific to the high side of the range Band cushion; // Data relevant to cushions on both sides of the range Band wall; // Data relevant to walls on both sides of the range } // Range data singleton. See range(). Range internal _range; /// @notice Threshold factor for the change, a percent in 2 decimals (i.e. 1000 = 10%). Determines how much of the capacity must be spent before the side is taken down. /// @dev A threshold is required so that a wall is not "active" with a capacity near zero, but unable to be depleted practically (dust). uint256 public thresholdFactor; /// @notice OHM token contract address ERC20 public ohm; /// @notice Reserve token contract address ERC20 public reserve; // ========= FUNCTIONS ========= // /// @notice Update the capacity for a side of the range. /// @notice Access restricted to activated policies. /// @param high_ - Specifies the side of the range to update capacity for (true = high side, false = low side). /// @param capacity_ - Amount to set the capacity to (OHM tokens for high side, Reserve tokens for low side). function updateCapacity(bool high_, uint256 capacity_) external virtual; /// @notice Update the prices for the low and high sides. /// @notice Access restricted to activated policies. /// @param movingAverage_ - Current moving average price to set range prices from. function updatePrices(uint256 movingAverage_) external virtual; /// @notice Regenerate a side of the range to a specific capacity. /// @notice Access restricted to activated policies. /// @param high_ - Specifies the side of the range to regenerate (true = high side, false = low side). /// @param capacity_ - Amount to set the capacity to (OHM tokens for high side, Reserve tokens for low side). function regenerate(bool high_, uint256 capacity_) external virtual; /// @notice Update the market ID (cushion) for a side of the range. /// @notice Access restricted to activated policies. /// @param high_ - Specifies the side of the range to update market for (true = high side, false = low side). /// @param market_ - Market ID to set for the side. /// @param marketCapacity_ - Amount to set the last market capacity to (OHM tokens for high side, Reserve tokens for low side). function updateMarket( bool high_, uint256 market_, uint256 marketCapacity_ ) external virtual; /// @notice Set the wall and cushion spreads. /// @notice Access restricted to activated policies. /// @param cushionSpread_ - Percent spread to set the cushions at above/below the moving average, assumes 2 decimals (i.e. 1000 = 10%). /// @param wallSpread_ - Percent spread to set the walls at above/below the moving average, assumes 2 decimals (i.e. 1000 = 10%). /// @dev The new spreads will not go into effect until the next time updatePrices() is called. function setSpreads(uint256 cushionSpread_, uint256 wallSpread_) external virtual; /// @notice Set the threshold factor for when a wall is considered "down". /// @notice Access restricted to activated policies. /// @param thresholdFactor_ - Percent of capacity that the wall should close below, assumes 2 decimals (i.e. 1000 = 10%). /// @dev The new threshold factor will not go into effect until the next time regenerate() is called for each side of the wall. function setThresholdFactor(uint256 thresholdFactor_) external virtual; /// @notice Get the full Range data in a struct. function range() external view virtual returns (Range memory); /// @notice Get the capacity for a side of the range. /// @param high_ - Specifies the side of the range to get capacity for (true = high side, false = low side). function capacity(bool high_) external view virtual returns (uint256); /// @notice Get the status of a side of the range (whether it is active or not). /// @param high_ - Specifies the side of the range to get status for (true = high side, false = low side). function active(bool high_) external view virtual returns (bool); /// @notice Get the price for the wall or cushion for a side of the range. /// @param wall_ - Specifies the band to get the price for (true = wall, false = cushion). /// @param high_ - Specifies the side of the range to get the price for (true = high side, false = low side). function price(bool wall_, bool high_) external view virtual returns (uint256); /// @notice Get the spread for the wall or cushion band. /// @param wall_ - Specifies the band to get the spread for (true = wall, false = cushion). function spread(bool wall_) external view virtual returns (uint256); /// @notice Get the market ID for a side of the range. /// @param high_ - Specifies the side of the range to get market for (true = high side, false = low side). function market(bool high_) external view virtual returns (uint256); /// @notice Get the timestamp when the range was last active. /// @param high_ - Specifies the side of the range to get timestamp for (true = high side, false = low side). function lastActive(bool high_) external view virtual returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import {ROLESv1} from "src/modules/ROLES/ROLES.v1.sol"; import "src/Kernel.sol"; /// @notice Abstract contract to have the `onlyRole` modifier /// @dev Inheriting this automatically makes ROLES module a dependency abstract contract RolesConsumer { ROLESv1 public ROLES; modifier onlyRole(bytes32 role_) { ROLES.requireRole(role_, msg.sender); _; } } /// @notice Module that holds multisig roles needed by various policies. contract OlympusRoles is ROLESv1 { //============================================================================================// // MODULE SETUP // //============================================================================================// constructor(Kernel kernel_) Module(kernel_) {} /// @inheritdoc Module function KEYCODE() public pure override returns (Keycode) { return toKeycode("ROLES"); } /// @inheritdoc Module function VERSION() external pure override returns (uint8 major, uint8 minor) { major = 1; minor = 0; } //============================================================================================// // CORE FUNCTIONS // //============================================================================================// /// @inheritdoc ROLESv1 function saveRole(bytes32 role_, address addr_) external override permissioned { if (hasRole[addr_][role_]) revert ROLES_AddressAlreadyHasRole(addr_, role_); ensureValidRole(role_); // Grant role to the address hasRole[addr_][role_] = true; emit RoleGranted(role_, addr_); } /// @inheritdoc ROLESv1 function removeRole(bytes32 role_, address addr_) external override permissioned { if (!hasRole[addr_][role_]) revert ROLES_AddressDoesNotHaveRole(addr_, role_); hasRole[addr_][role_] = false; emit RoleRevoked(role_, addr_); } //============================================================================================// // VIEW FUNCTIONS // //============================================================================================// /// @inheritdoc ROLESv1 function requireRole(bytes32 role_, address caller_) external view override { if (!hasRole[caller_][role_]) revert ROLES_RequireRole(role_); } /// @inheritdoc ROLESv1 function ensureValidRole(bytes32 role_) public pure override { for (uint256 i = 0; i < 32; ) { bytes1 char = role_[i]; if ((char < 0x61 || char > 0x7A) && char != 0x5f && char != 0x00) { revert ROLES_InvalidRole(role_); // a-z only } unchecked { i++; } } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import "src/Kernel.sol"; abstract contract ROLESv1 is Module { // ========= EVENTS ========= // event RoleGranted(bytes32 indexed role_, address indexed addr_); event RoleRevoked(bytes32 indexed role_, address indexed addr_); // ========= ERRORS ========= // error ROLES_InvalidRole(bytes32 role_); error ROLES_RequireRole(bytes32 role_); error ROLES_AddressAlreadyHasRole(address addr_, bytes32 role_); error ROLES_AddressDoesNotHaveRole(address addr_, bytes32 role_); error ROLES_RoleDoesNotExist(bytes32 role_); // ========= STATE ========= // /// @notice Mapping for if an address has a policy-defined role. mapping(address => mapping(bytes32 => bool)) public hasRole; // ========= FUNCTIONS ========= // /// @notice Function to grant policy-defined roles to some address. Can only be called by admin. function saveRole(bytes32 role_, address addr_) external virtual; /// @notice Function to revoke policy-defined roles from some address. Can only be called by admin. function removeRole(bytes32 role_, address addr_) external virtual; /// @notice "Modifier" to restrict policy function access to certain addresses with a role. /// @dev Roles are defined in the policy and granted by the ROLES admin. function requireRole(bytes32 role_, address caller_) external virtual; /// @notice Function that checks if role is valid (all lower case) function ensureValidRole(bytes32 role_) external pure virtual; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import {ERC20} from "solmate/tokens/ERC20.sol"; import "src/Kernel.sol"; /// @notice Treasury holds all other assets under the control of the protocol. abstract contract TRSRYv1 is Module { // ========= EVENTS ========= // event IncreaseWithdrawApproval( address indexed withdrawer_, ERC20 indexed token_, uint256 newAmount_ ); event DecreaseWithdrawApproval( address indexed withdrawer_, ERC20 indexed token_, uint256 newAmount_ ); event Withdrawal( address indexed policy_, address indexed withdrawer_, ERC20 indexed token_, uint256 amount_ ); event IncreaseDebtorApproval(address indexed debtor_, ERC20 indexed token_, uint256 newAmount_); event DecreaseDebtorApproval(address indexed debtor_, ERC20 indexed token_, uint256 newAmount_); event DebtIncurred(ERC20 indexed token_, address indexed policy_, uint256 amount_); event DebtRepaid(ERC20 indexed token_, address indexed policy_, uint256 amount_); event DebtSet(ERC20 indexed token_, address indexed policy_, uint256 amount_); // ========= ERRORS ========= // error TRSRY_NoDebtOutstanding(); error TRSRY_NotActive(); // ========= STATE ========= // /// @notice Status of the treasury. If false, no withdrawals or debt can be incurred. bool public active; /// @notice Mapping of who is approved for withdrawal. /// @dev withdrawer -> token -> amount. Infinite approval is max(uint256). mapping(address => mapping(ERC20 => uint256)) public withdrawApproval; /// @notice Mapping of who is approved to incur debt. /// @dev debtor -> token -> amount. Infinite approval is max(uint256). mapping(address => mapping(ERC20 => uint256)) public debtApproval; /// @notice Total debt for token across all withdrawals. mapping(ERC20 => uint256) public totalDebt; /// @notice Debt for particular token and debtor address mapping(ERC20 => mapping(address => uint256)) public reserveDebt; // ========= FUNCTIONS ========= // modifier onlyWhileActive() { if (!active) revert TRSRY_NotActive(); _; } /// @notice Increase approval for specific withdrawer addresses function increaseWithdrawApproval( address withdrawer_, ERC20 token_, uint256 amount_ ) external virtual; /// @notice Decrease approval for specific withdrawer addresses function decreaseWithdrawApproval( address withdrawer_, ERC20 token_, uint256 amount_ ) external virtual; /// @notice Allow withdrawal of reserve funds from pre-approved addresses. function withdrawReserves( address to_, ERC20 token_, uint256 amount_ ) external virtual; /// @notice Increase approval for someone to accrue debt in order to withdraw reserves. /// @dev Debt will generally be taken by contracts to allocate treasury funds in yield sources. function increaseDebtorApproval( address debtor_, ERC20 token_, uint256 amount_ ) external virtual; /// @notice Decrease approval for someone to withdraw reserves as debt. function decreaseDebtorApproval( address debtor_, ERC20 token_, uint256 amount_ ) external virtual; /// @notice Pre-approved policies can get a loan to perform operations with treasury assets. function incurDebt(ERC20 token_, uint256 amount_) external virtual; /// @notice Repay a debtor debt. /// @dev Only confirmed to safely handle standard and non-standard ERC20s. /// @dev Can have unforeseen consequences with ERC777. Be careful with ERC777 as reserve. function repayDebt( address debtor_, ERC20 token_, uint256 amount_ ) external virtual; /// @notice An escape hatch for setting debt in special cases, like swapping reserves to another token. function setDebt( address debtor_, ERC20 token_, uint256 amount_ ) external virtual; /// @notice Get total balance of assets inside the treasury + any debt taken out against those assets. function getReserveBalance(ERC20 token_) external view virtual returns (uint256); /// @notice Emergency shutdown of withdrawals. function deactivate() external virtual; /// @notice Re-activate withdrawals after shutdown. function activate() external virtual; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.0; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IBondSDA} from "interfaces/IBondSDA.sol"; import {IBondCallback} from "interfaces/IBondCallback.sol"; interface IOperator { // ========= EVENTS ========= // event Swap( ERC20 indexed tokenIn_, ERC20 indexed tokenOut_, uint256 amountIn_, uint256 amountOut_ ); event CushionFactorChanged(uint32 cushionFactor_); event CushionParamsChanged(uint32 duration_, uint32 debtBuffer_, uint32 depositInterval_); event ReserveFactorChanged(uint32 reserveFactor_); event RegenParamsChanged(uint32 wait_, uint32 threshold_, uint32 observe_); // ========= ERRORS ========= // error Operator_InvalidParams(); error Operator_InsufficientCapacity(); error Operator_AmountLessThanMinimum(uint256 amountOut, uint256 minAmountOut); error Operator_WallDown(); error Operator_AlreadyInitialized(); error Operator_NotInitialized(); error Operator_Inactive(); // ========= STRUCTS ========== // /// @notice Configuration variables for the Operator struct Config { uint32 cushionFactor; // percent of capacity to be used for a single cushion deployment, assumes 2 decimals (i.e. 1000 = 10%) uint32 cushionDuration; // duration of a single cushion deployment in seconds uint32 cushionDebtBuffer; // Percentage over the initial debt to allow the market to accumulate at any one time. Percent with 3 decimals, e.g. 1_000 = 1 %. See IBondSDA for more info. uint32 cushionDepositInterval; // Target frequency of deposits. Determines max payout of the bond market. See IBondSDA for more info. uint32 reserveFactor; // percent of reserves in treasury to be used for a single wall, assumes 2 decimals (i.e. 1000 = 10%) uint32 regenWait; // minimum duration to wait to reinstate a wall in seconds uint32 regenThreshold; // number of price points on other side of moving average to reinstate a wall uint32 regenObserve; // number of price points to observe to determine regeneration } /// @notice Combines regeneration status for low and high sides of the range struct Status { Regen low; // regeneration status for the low side of the range Regen high; // regeneration status for the high side of the range } /// @notice Tracks status of when a specific side of the range can be regenerated by the Operator struct Regen { uint32 count; // current number of price points that count towards regeneration uint48 lastRegen; // timestamp of the last regeneration uint32 nextObservation; // index of the next observation in the observations array bool[] observations; // individual observations: true = price on other side of average, false = price on same side of average } // ========= CORE FUNCTIONS ========= // /// @notice Executes market operations logic. /// @notice Access restricted /// @dev This function is triggered by a keeper on the Heart contract. function operate() external; // ========= OPEN MARKET OPERATIONS (WALL) ========= // /// @notice Swap at the current wall prices /// @param tokenIn_ - Token to swap into the wall /// - OHM: swap at the low wall price for Reserve /// - Reserve: swap at the high wall price for OHM /// @param amountIn_ - Amount of tokenIn to swap /// @param minAmountOut_ - Minimum amount of opposite token to receive /// @return amountOut - Amount of opposite token received function swap( ERC20 tokenIn_, uint256 amountIn_, uint256 minAmountOut_ ) external returns (uint256 amountOut); /// @notice Returns the amount to be received from a swap /// @param tokenIn_ - Token to swap into the wall /// - If OHM: swap at the low wall price for Reserve /// - If Reserve: swap at the high wall price for OHM /// @param amountIn_ - Amount of tokenIn to swap /// @return Amount of opposite token received function getAmountOut(ERC20 tokenIn_, uint256 amountIn_) external view returns (uint256); // ========= ADMIN FUNCTIONS ========= // /// @notice Set the wall and cushion spreads /// @notice Access restricted /// @dev Interface for externally setting these values on the RANGE module /// @param cushionSpread_ - Percent spread to set the cushions at above/below the moving average, assumes 2 decimals (i.e. 1000 = 10%) /// @param wallSpread_ - Percent spread to set the walls at above/below the moving average, assumes 2 decimals (i.e. 1000 = 10%) function setSpreads(uint256 cushionSpread_, uint256 wallSpread_) external; /// @notice Set the threshold factor for when a wall is considered "down" /// @notice Access restricted /// @dev Interface for externally setting this value on the RANGE module /// @param thresholdFactor_ - Percent of capacity that the wall should close below, assumes 2 decimals (i.e. 1000 = 10%) function setThresholdFactor(uint256 thresholdFactor_) external; /// @notice Set the cushion factor /// @notice Access restricted /// @param cushionFactor_ - Percent of wall capacity that the operator will deploy in the cushion, assumes 2 decimals (i.e. 1000 = 10%) function setCushionFactor(uint32 cushionFactor_) external; /// @notice Set the parameters used to deploy cushion bond markets /// @notice Access restricted /// @param duration_ - Duration of cushion bond markets in seconds /// @param debtBuffer_ - Percentage over the initial debt to allow the market to accumulate at any one time. Percent with 3 decimals, e.g. 1_000 = 1 %. See IBondSDA for more info. /// @param depositInterval_ - Target frequency of deposits in seconds. Determines max payout of the bond market. See IBondSDA for more info. function setCushionParams( uint32 duration_, uint32 debtBuffer_, uint32 depositInterval_ ) external; /// @notice Set the reserve factor /// @notice Access restricted /// @param reserveFactor_ - Percent of treasury reserves to deploy as capacity for market operations, assumes 2 decimals (i.e. 1000 = 10%) function setReserveFactor(uint32 reserveFactor_) external; /// @notice Set the wall regeneration parameters /// @notice Access restricted /// @param wait_ - Minimum duration to wait to reinstate a wall in seconds /// @param threshold_ - Number of price points on other side of moving average to reinstate a wall /// @param observe_ - Number of price points to observe to determine regeneration /// @dev We must see Threshold number of price points that meet our criteria within the last Observe number of price points to regenerate a wall. function setRegenParams( uint32 wait_, uint32 threshold_, uint32 observe_ ) external; /// @notice Set the contracts that the Operator deploys bond markets with. /// @notice Access restricted /// @param auctioneer_ - Address of the bond auctioneer to use. /// @param callback_ - Address of the callback to use. function setBondContracts(IBondSDA auctioneer_, IBondCallback callback_) external; /// @notice Initialize the Operator to begin market operations /// @notice Access restricted /// @notice Can only be called once /// @dev This function executes actions required to start operations that cannot be done prior to the Operator policy being approved by the Kernel. function initialize() external; /// @notice Regenerate the wall for a side /// @notice Access restricted /// @param high_ Whether to regenerate the high side or low side (true = high, false = low) /// @dev This function is an escape hatch to trigger out of cycle regenerations and may be useful when doing migrations of Treasury funds function regenerate(bool high_) external; /// @notice Deactivate the Operator /// @notice Access restricted /// @dev Emergency pause function for the Operator. Prevents market operations from occurring. function deactivate() external; /// @notice Activate the Operator /// @notice Access restricted /// @dev Restart function for the Operator after a pause. function activate() external; /// @notice Manually close a cushion bond market /// @notice Access restricted /// @param high_ Whether to deactivate the high or low side cushion (true = high, false = low) /// @dev Emergency shutdown function for Cushions function deactivateCushion(bool high_) external; // ========= VIEW FUNCTIONS ========= // /// @notice Returns the full capacity of the specified wall (if it was regenerated now) /// @dev Calculates the capacity to deploy for a wall based on the amount of reserves owned by the treasury and the reserve factor. /// @param high_ - Whether to return the full capacity for the high or low wall function fullCapacity(bool high_) external view returns (uint256); /// @notice Returns the status variable of the Operator as a Status struct function status() external view returns (Status memory); /// @notice Returns the config variable of the Operator as a Config struct function config() external view returns (Config memory); }
{ "remappings": [ "balancer-v2/=lib/balancer-v2/", "bonds/=lib/bonds/src/", "ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "interfaces/=src/interfaces/", "libraries/=src/libraries/", "modules/=src/modules/", "policies/=src/policies/", "solmate/=lib/solmate/src/", "test/=src/test/" ], "optimizer": { "enabled": true, "runs": 10 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract Kernel","name":"kernel_","type":"address"},{"internalType":"contract IBondSDA","name":"auctioneer_","type":"address"},{"internalType":"contract IBondCallback","name":"callback_","type":"address"},{"internalType":"contract ERC20[2]","name":"tokens_","type":"address[2]"},{"internalType":"uint32[8]","name":"configParams","type":"uint32[8]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"caller_","type":"address"}],"name":"KernelAdapter_OnlyKernel","type":"error"},{"inputs":[],"name":"Operator_AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"Operator_AmountLessThanMinimum","type":"error"},{"inputs":[],"name":"Operator_Inactive","type":"error"},{"inputs":[],"name":"Operator_InsufficientCapacity","type":"error"},{"inputs":[],"name":"Operator_InvalidParams","type":"error"},{"inputs":[],"name":"Operator_NotInitialized","type":"error"},{"inputs":[],"name":"Operator_WallDown","type":"error"},{"inputs":[{"internalType":"Keycode","name":"keycode_","type":"bytes5"}],"name":"Policy_ModuleDoesNotExist","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"cushionFactor_","type":"uint32"}],"name":"CushionFactorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"duration_","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"debtBuffer_","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"depositInterval_","type":"uint32"}],"name":"CushionParamsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"wait_","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"threshold_","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"observe_","type":"uint32"}],"name":"RegenParamsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"reserveFactor_","type":"uint32"}],"name":"ReserveFactorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ERC20","name":"tokenIn_","type":"address"},{"indexed":true,"internalType":"contract ERC20","name":"tokenOut_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut_","type":"uint256"}],"name":"Swap","type":"event"},{"inputs":[],"name":"ONE_HUNDRED_PERCENT","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_PERCENT","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLES","outputs":[{"internalType":"contract ROLESv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"active","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctioneer","outputs":[{"internalType":"contract IBondSDA","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"amountOut_","type":"uint256"}],"name":"bondPurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"callback","outputs":[{"internalType":"contract IBondCallback","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Kernel","name":"newKernel_","type":"address"}],"name":"changeKernel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"config","outputs":[{"components":[{"internalType":"uint32","name":"cushionFactor","type":"uint32"},{"internalType":"uint32","name":"cushionDuration","type":"uint32"},{"internalType":"uint32","name":"cushionDebtBuffer","type":"uint32"},{"internalType":"uint32","name":"cushionDepositInterval","type":"uint32"},{"internalType":"uint32","name":"reserveFactor","type":"uint32"},{"internalType":"uint32","name":"regenWait","type":"uint32"},{"internalType":"uint32","name":"regenThreshold","type":"uint32"},{"internalType":"uint32","name":"regenObserve","type":"uint32"}],"internalType":"struct IOperator.Config","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"configureDependencies","outputs":[{"internalType":"Keycode[]","name":"dependencies","type":"bytes5[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deactivate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"high_","type":"bool"}],"name":"deactivateCushion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"high_","type":"bool"}],"name":"fullCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"tokenIn_","type":"address"},{"internalType":"uint256","name":"amountIn_","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kernel","outputs":[{"internalType":"contract Kernel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ohm","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ohmDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"high_","type":"bool"}],"name":"regenerate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestPermissions","outputs":[{"components":[{"internalType":"Keycode","name":"keycode","type":"bytes5"},{"internalType":"bytes4","name":"funcSelector","type":"bytes4"}],"internalType":"struct Permissions[]","name":"requests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserve","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserveDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBondSDA","name":"auctioneer_","type":"address"},{"internalType":"contract IBondCallback","name":"callback_","type":"address"}],"name":"setBondContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"cushionFactor_","type":"uint32"}],"name":"setCushionFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"duration_","type":"uint32"},{"internalType":"uint32","name":"debtBuffer_","type":"uint32"},{"internalType":"uint32","name":"depositInterval_","type":"uint32"}],"name":"setCushionParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"wait_","type":"uint32"},{"internalType":"uint32","name":"threshold_","type":"uint32"},{"internalType":"uint32","name":"observe_","type":"uint32"}],"name":"setRegenParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"reserveFactor_","type":"uint32"}],"name":"setReserveFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cushionSpread_","type":"uint256"},{"internalType":"uint256","name":"wallSpread_","type":"uint256"}],"name":"setSpreads","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"thresholdFactor_","type":"uint256"}],"name":"setThresholdFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"status","outputs":[{"components":[{"components":[{"internalType":"uint32","name":"count","type":"uint32"},{"internalType":"uint48","name":"lastRegen","type":"uint48"},{"internalType":"uint32","name":"nextObservation","type":"uint32"},{"internalType":"bool[]","name":"observations","type":"bool[]"}],"internalType":"struct IOperator.Regen","name":"low","type":"tuple"},{"components":[{"internalType":"uint32","name":"count","type":"uint32"},{"internalType":"uint48","name":"lastRegen","type":"uint48"},{"internalType":"uint32","name":"nextObservation","type":"uint32"},{"internalType":"bool[]","name":"observations","type":"bool[]"}],"internalType":"struct IOperator.Regen","name":"high","type":"tuple"}],"internalType":"struct IOperator.Status","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"tokenIn_","type":"address"},{"internalType":"uint256","name":"amountIn_","type":"uint256"},{"internalType":"uint256","name":"minAmountOut_","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
61010060405260016002553480156200001757600080fd5b5060405162006c8438038062006c848339810160408190526200003a9162000a75565b600080546001600160a01b0319166001600160a01b0387811691909117909155841615806200007057506001600160a01b038316155b156200008f5760405163042a67ad60e41b815260040160405180910390fd5b62093a80816001602002015163ffffffff161180620000bd575062015180816001602002015163ffffffff16105b15620000dc5760405163042a67ad60e41b815260040160405180910390fd5b612710816002602002015163ffffffff1610156200010d5760405163042a67ad60e41b815260040160405180910390fd5b610e10816003602002015163ffffffff1610806200013c57506020810151606082015163ffffffff9182169116115b156200015b5760405163042a67ad60e41b815260040160405180910390fd5b805161271063ffffffff90911611806200017e57508051606463ffffffff909116105b156200019d5760405163042a67ad60e41b815260040160405180910390fd5b612710816004602002015163ffffffff161180620001c857506064816004602002015163ffffffff16105b15620001e75760405163042a67ad60e41b815260040160405180910390fd5b610e10816005602002015163ffffffff16108062000216575060e081015160c082015163ffffffff9182169116115b806200022a575060e081015163ffffffff16155b806200023e575060c081015163ffffffff16155b156200025d5760405163042a67ad60e41b815260040160405180910390fd5b600c80546001600160a01b038681166001600160a01b031992831617909255600d805486841692169190911790558251811660805282516040805163313ce56760e01b81529051919092169163313ce5679160048083019260209291908290030181865afa158015620002d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fa919062000b52565b60ff1660a05281600160200201516001600160a01b031660c05281600160200201516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200035a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000380919062000b52565b60ff1660e05260408051608081018252600080825265ffffffffffff4216602083015291810182905260608101836007602002015163ffffffff166001600160401b03811115620003d557620003d562000994565b604051908082528060200260200182016040528015620003ff578160200160208202803683370190505b5090526040805161010081018252845163ffffffff908116825260208087015182169083015285830151169181019190915290915060608101836003602002015163ffffffff1681526020018360046008811062000461576200046162000b3c565b602002015163ffffffff1681526020018360056008811062000487576200048762000b3c565b602002015163ffffffff16815260200183600660088110620004ad57620004ad62000b3c565b602002015163ffffffff16815260200183600760088110620004d357620004d362000b3c565b602002015163ffffffff16815250600760008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600001601c6101000a81548163ffffffff021916908363ffffffff160217905550905050604051806040016040528082815260200182815250600360008201518160000160008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548165ffffffffffff021916908365ffffffffffff160217905550604082015181600001600a6101000a81548163ffffffff021916908363ffffffff1602179055506060820151816001019080519060200190620006d5929190620008b8565b505050602082810151805160028401805483850151604085015163ffffffff9081166a01000000000000000000000263ffffffff60501b1965ffffffffffff909316640100000000026001600160501b0319909416919095161791909117169190911781556060820151805192939192620007579260038701920190620008b8565b5050509050507f5760955ed2acbd2b290c0a6edf1c0bc845f64f1da0b9f89582fac3daade8dff58260006008811062000794576200079462000b3c565b6020020151604051620007b3919063ffffffff91909116815260200190565b60405180910390a1602080830151604080850151606080870151835163ffffffff95861681529285169583019590955292909316908301527f6627cd780fa2d7faf558f4d9d700a0852b79903fd60ce8c0f734103cf8aa12b8910160405180910390a1608082015160405163ffffffff90911681527fb3f67f3c41e3a7c2c87b93a1c1fe4581744242b44b44d4a873ca8facec1ee8a59060200160405180910390a160a082015160c083015160e08401516040805163ffffffff9485168152928416602084015292168183015290517f9f11b1d829316eb1d4d6f91541c83d9f78bc1e309f755c759d190c973f7b4fae9181900360600190a150505050505062000b7e565b82805482825590600052602060002090601f01602090048101928215620009525791602002820160005b838211156200092157835183826101000a81548160ff0219169083151502179055509260200192600101602081600001049283019260010302620008e2565b8015620009505782816101000a81549060ff021916905560010160208160000104928301926001030262000921565b505b506200096092915062000964565b5090565b5b8082111562000960576000815560010162000965565b6001600160a01b03811681146200099157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715620009db57634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f830112620009f357600080fd5b6040516101008082016001600160401b038111838210171562000a2657634e487b7160e01b600052604160045260246000fd5b6040528301818582111562000a3a57600080fd5b845b8281101562000a6a57805163ffffffff8116811462000a5b5760008081fd5b82526020918201910162000a3c565b509195945050505050565b60008060008060006101a0868803121562000a8f57600080fd5b855162000a9c816200097b565b8095505060208087015162000ab1816200097b565b604088015190955062000ac4816200097b565b9350607f8701881362000ad657600080fd5b62000ae0620009aa565b8060a089018a81111562000af357600080fd5b60608a015b8181101562000b1c57805162000b0e816200097b565b845292840192840162000af8565b5081955062000b2c8b82620009e1565b9450505050509295509295909350565b634e487b7160e01b600052603260045260246000fd5b60006020828403121562000b6557600080fd5b815160ff8116811462000b7757600080fd5b9392505050565b60805160a05160c05160e051615fec62000c98600039600081816103060152818161222501528181612d6e01528181613f9d015281816140a5015281816146ab01526146f90152600081816104f201528181611fcd015281816125cd0152818161262b015281816126ab015281816127c30152818161287e01528181612ee30152818161350b015281816135a30152818161363d0152818161427601526148350152600081816104a30152818161217c01528181612e2501528181613fbe015281816140840152818161468a015261471a0152600081816101c001528181611f720152818161241101528181612517015281816126550152818161285401528181612cb70152818161424701526148640152615fec6000f3fe608060405234801561001057600080fd5b50600436106101a15760003560e01c806301de9ba8146101a657806302b1d239146101bb57806302fb0c5e146101f8578063083b27321461021a5780630f15f4c01461022d578063158ef93e1461023557806319f63dd714610242578063200d2ed21461025557806322f3e2d41461026a5780632ecd1f201461027257806333bd33b4146102855780633a3f54bc1461029857806341f19a46146102ab5780634657b36c146102be57806351b42b00146102d15780635924be70146102d95780635ec2c7bf146102ee5780636e703c2e146103015780637159a6181461033a57806379502c55146103425780638129fc1c14610414578063923cb9521461041c5780639459b8751461042f5780639e897711146104445780639f1d0f5914610465578063aa9760a114610478578063ab1047711461048b578063aea564af1461049e578063bb2eb4d2146104c5578063ca706bcf146104da578063cd3293de146104ed578063d4aae0c414610514578063dd0081c714610527578063f2f6d5bb14610530578063f2fa473714610543575b600080fd5b6101b96101b436600461535b565b610556565b005b6101e27f000000000000000000000000000000000000000000000000000000000000000081565b6040516101ef9190615383565b60405180910390f35b60085461020a90610100900460ff1681565b60405190151581526020016101ef565b600d546101e2906001600160a01b031681565b6101b9610666565b60085461020a9060ff1681565b6101b96102503660046153ac565b6106ee565b61025d6107ce565b6040516101ef9190615465565b61020a610956565b6101b96102803660046154b5565b6109cd565b6101b96102933660046154d2565b610a4f565b6101b96102a63660046154eb565b610b28565b6101b96102b936600461552e565b610e14565b6101b96102cc366004615550565b610efb565b6101b9610f53565b6102e1610fec565b6040516101ef919061556d565b600c546101e2906001600160a01b031681565b6103287f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101ef565b6101b961158f565b6104076040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915250604080516101008101825260075463ffffffff8082168352600160201b820481166020840152600160401b8204811693830193909352600160601b810483166060830152600160801b810483166080830152600160a01b8104831660a0830152600160c01b8104831660c0830152600160e01b900490911660e082015290565b6040516101ef91906155d0565b6101b9611c24565b6001546101e2906001600160a01b031681565b610437611ced565b6040516101ef9190615657565b6104576104523660046154b5565b611fa0565b6040519081526020016101ef565b6104576104733660046156a5565b61227b565b6101b961048636600461535b565b6128ea565b6101b961049936600461552e565b6129e5565b6103287f000000000000000000000000000000000000000000000000000000000000000081565b6104cd606481565b6040516101ef91906156da565b6104576104e83660046156eb565b612cb3565b6101e27f000000000000000000000000000000000000000000000000000000000000000081565b6000546101e2906001600160a01b031681565b6104cd61271081565b6101b961053e3660046154b5565b612faa565b6101b96105513660046154eb565b613029565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c59061059a9084903390600401615717565b600060405180830381600087803b1580156105b457600080fd5b505af11580156105c8573d6000803e3d6000fd5b5050505061271063ffffffff168263ffffffff1611806105ee5750606463ffffffff8316105b1561060c5760405163042a67ad60e41b815260040160405180910390fd5b6007805463ffffffff60801b1916600160801b63ffffffff8516021790556040517fb3f67f3c41e3a7c2c87b93a1c1fe4581744242b44b44d4a873ca8facec1ee8a59061065a9084906156da565b60405180910390a15050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c5906106aa9084903390600401615717565b600060405180830381600087803b1580156106c457600080fd5b505af11580156106d8573d6000803e3d6000fd5b50506008805461ff001916610100179055505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c5906107329084903390600401615717565b600060405180830381600087803b15801561074c57600080fd5b505af1158015610760573d6000803e3d6000fd5b505050506001600160a01b038316158061078157506001600160a01b038216155b1561079f5760405163042a67ad60e41b815260040160405180910390fd5b50600c80546001600160a01b039384166001600160a01b031991821617909155600d8054929093169116179055565b6107d661523d565b6040805160c0810182526003805463ffffffff80821684860190815265ffffffffffff600160201b8404166060860152600160501b909204166080840152600480548551602082810282018101909752818152949593948694869360a0870193909183018282801561088757602002820191906000526020600020906000905b825461010083900a900460ff1615158152602060019283018181049485019490930390920291018084116108565790505b5050509190925250505081526040805160808101825260028401805463ffffffff808216845265ffffffffffff600160201b830416602085810191909152600160501b9092041683850152600386018054855181840281018401909652808652958201959394929360608601939283018282801561094457602002820191906000526020600020906000905b825461010083900a900460ff1615158152602060019283018181049485019490930390920291018084116109135790505b50505050508152505081525050905090565b6000805460405163e52223bb60e01b81526001600160a01b039091169063e52223bb90610987903090600401615383565b602060405180830381865afa1580156109a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c8919061572e565b905090565b60015460405163d09a20c560e01b81526d37b832b930ba37b92fb0b236b4b760911b916001600160a01b03169063d09a20c590610a109084903390600401615717565b600060405180830381600087803b158015610a2a57600080fd5b505af1158015610a3e573d6000803e3d6000fd5b50505050610a4b826131cb565b5050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610a939084903390600401615717565b600060405180830381600087803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b5050600954604051630cef4ced60e21b8152600481018690526001600160a01b0390911692506333bd33b491506024015b600060405180830381600087803b158015610b0c57600080fd5b505af1158015610b20573d6000803e3d6000fd5b505050505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610b6c9084903390600401615717565b600060405180830381600087803b158015610b8657600080fd5b505af1158015610b9a573d6000803e3d6000fd5b50505050610e108463ffffffff161080610bbf57508163ffffffff168363ffffffff16115b80610bce575063ffffffff8216155b80610bdd575063ffffffff8316155b80610c845750610bed8383615761565b63ffffffff16600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6a919061579c565b610c7a9063ffffffff87166157cd565b65ffffffffffff16105b15610ca25760405163042a67ad60e41b815260040160405180910390fd5b60078054600160a01b600160e01b031916600160a01b63ffffffff8781169190910263ffffffff60c01b191691909117600160c01b86831602176001600160e01b0316600160e01b918516918202179091556005805463ffffffff63ffffffff60501b01191690556001600160401b03811115610d2157610d216157f2565b604051908082528060200260200182016040528015610d4a578160200160208202803683370190505b508051610d5f91600691602090910190615262565b506003805463ffffffff63ffffffff60501b011916905563ffffffff82166001600160401b03811115610d9457610d946157f2565b604051908082528060200260200182016040528015610dbd578160200160208202803683370190505b508051610dd291600491602090910190615262565b507f9f11b1d829316eb1d4d6f91541c83d9f78bc1e309f755c759d190c973f7b4fae848484604051610e0693929190615808565b60405180910390a150505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610e589084903390600401615717565b600060405180830381600087803b158015610e7257600080fd5b505af1158015610e86573d6000803e3d6000fd5b50506009546040516320f8cd2360e11b81526001600160a01b0390911692506341f19a469150610ebc9086908690600401615828565b600060405180830381600087803b158015610ed657600080fd5b505af1158015610eea573d6000803e3d6000fd5b50505050610ef66136ed565b505050565b6000546001600160a01b03163314610f31573360405163053e900f60e21b8152600401610f289190615383565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610f979084903390600401615717565b600060405180830381600087803b158015610fb157600080fd5b505af1158015610fc5573d6000803e3d6000fd5b50506008805461ff001916905550610fdf905060016137c8565b610fe960006137c8565b50565b60606000600960009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611043573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110679190615836565b90506000600a60009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e29190615836565b90506000600b60009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115d9190615836565b60408051600d8082526101c08201909252919250816020015b6040805180820190915260008082526020820152815260200190600190039081611176575050604080518082019091526001600160d81b0319851681526336cd4d3160e11b602082015281519195509085906000906111d7576111d7615860565b60200260200101819052506040518060400160405280846001600160d81b0319168152602001633e56993a60e01b6001600160e01b0319168152508460018151811061122557611225615860565b60200260200101819052506040518060400160405280846001600160d81b031916815260200163ae7e8d8160e01b6001600160e01b0319168152508460028151811061127357611273615860565b60200260200101819052506040518060400160405280846001600160d81b031916815260200162d1673960e01b6001600160e01b031916815250846003815181106112c0576112c0615860565b60200260200101819052506040518060400160405280846001600160d81b03191681526020016341f19a4660e01b6001600160e01b0319168152508460048151811061130e5761130e615860565b60200260200101819052506040518060400160405280846001600160d81b03191681526020016333bd33b460e01b6001600160e01b0319168152508460058151811061135c5761135c615860565b60200260200101819052506040518060400160405280836001600160d81b0319168152602001632f42aef560e01b6001600160e01b031916815250846006815181106113aa576113aa615860565b60200260200101819052506040518060400160405280836001600160d81b031916815260200163e6eb207a60e01b6001600160e01b031916815250846007815181106113f8576113f8615860565b60200260200101819052506040518060400160405280836001600160d81b0319168152602001638b7f3fb960e01b6001600160e01b0319168152508460088151811061144657611446615860565b60200260200101819052506040518060400160405280826001600160d81b0319168152602001633a56e30760e01b6001600160e01b0319168152508460098151811061149457611494615860565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163aaf0ad5a60e01b6001600160e01b03191681525084600a815181106114e2576114e2615860565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163359fe78060e01b6001600160e01b03191681525084600b8151811061153057611530615860565b60200260200101819052506040518060400160405280826001600160d81b0319168152602001631b0a68f260e01b6001600160e01b03191681525084600c8151811061157e5761157e615860565b602002602001018190525050505090565b600854610100900460ff1615806116b75750600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611618919061579c565b611623906003615876565b600860029054906101000a90046001600160a01b03166001600160a01b031663d266f5d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611676573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169a919061579c565b6116a491906158a4565b65ffffffffffff164265ffffffffffff16115b156116d5576040516316b0245b60e21b815260040160405180910390fd5b60015460405163d09a20c560e01b81526f6f70657261746f725f6f70657261746560801b916001600160a01b03169063d09a20c59061171a9084903390600401615717565b600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b505060085460ff169150611771905057604051633cb84dd760e11b815260040160405180910390fd5b6117796136ed565b61178161393f565b604080516101008101825260075463ffffffff8082168352600160201b820481166020840152600160401b8204811683850152600160601b820481166060840152600160801b820481166080840152600160a01b8204811660a08401819052600160c01b8304821660c0850152600160e01b9092041660e0830152600954925163734f9e2760e11b815260016004820152919290916001600160a01b039091169063e69f3c4e90602401602060405180830381865afa158015611848573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186c91906158ce565b61187691906158e7565b4265ffffffffffff161015801561189d575060c081015160055463ffffffff918216911610155b156118ac576118ac60016131cb565b60a081015160095460405163734f9e2760e11b81526000600482015263ffffffff909216916001600160a01b039091169063e69f3c4e90602401602060405180830381865afa158015611903573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192791906158ce565b61193191906158e7565b4265ffffffffffff1610158015611958575060c081015160035463ffffffff918216911610155b156119675761196760006131cb565b6009546040805163e97206a960e01b815290516000926001600160a01b03169163e97206a9916004808301926102009291908290030181865afa1580156119b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d69190615a52565b90506000600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5191906158ce565b82515190915015611b3c57600c548251608001516040516304ea0e8b60e31b81526001600160a01b0390921691632750745891611a949160040190815260200190565b602060405180830381865afa158015611ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad5919061572e565b15611b0d5760408201516020015151811180611af957506060820151602001515181105b15611b0857611b0860006137c8565b611b3c565b6040820151602001515181108015611b2d57506060820151602001515181115b15611b3c57611b3c6000613eff565b60208201515115611c1e57600c546020830151608001516040516304ea0e8b60e31b81526001600160a01b0390921691632750745891611b829160040190815260200190565b602060405180830381865afa158015611b9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc3919061572e565b15611bf55760408201515151811080611be157506060820151515181115b15611bf057611bf060016137c8565b611c1e565b6040820151515181118015611c0f57506060820151515181105b15611c1e57611c1e6001613eff565b50505050565b60015460405163d09a20c560e01b81526d37b832b930ba37b92fb0b236b4b760911b916001600160a01b03169063d09a20c590611c679084903390600401615717565b600060405180830381600087803b158015611c8157600080fd5b505af1158015611c95573d6000803e3d6000fd5b505060085460ff16159150611cbf9050576040516358b8d27560e01b815260040160405180910390fd5b611cc76136ed565b611cd160016131cb565b611cdb60006131cb565b506008805461ffff1916610101179055565b60408051600580825260c082019092526060916020820160a08036833701905050905064505249434560d81b81600081518110611d2c57611d2c615860565b6001600160d81b031990921660209283029190910190910152611d546452414e474560d81b90565b81600181518110611d6757611d67615860565b6001600160d81b031990921660209283029190910190910152611d8f64545253525960d81b90565b81600281518110611da257611da2615860565b6001600160d81b031990921660209283029190910190910152611dca6426a4a72a2960d91b90565b81600381518110611ddd57611ddd615860565b6001600160d81b031990921660209283029190910190910152611e0564524f4c455360d81b90565b81600481518110611e1857611e18615860565b60200260200101906001600160d81b03191690816001600160d81b03191681525050611e5d81600081518110611e5057611e50615860565b6020026020010151614b16565b600860026101000a8154816001600160a01b0302191690836001600160a01b03160217905550611e9981600181518110611e5057611e50615860565b600960006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611ed581600281518110611e5057611e50615860565b600a60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611f1181600381518110611e5057611e50615860565b600b60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611f4d81600481518110611e5057611e50615860565b600180546001600160a01b0319166001600160a01b03928316179055600b54611f9d917f000000000000000000000000000000000000000000000000000000000000000081169116600019614bb3565b90565b600a546040516305489ad560e21b815260009182916001600160a01b03909116906315226b5490611ff5907f000000000000000000000000000000000000000000000000000000000000000090600401615383565b602060405180830381865afa158015612012573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203691906158ce565b6007549091506000906127109061205a90600160801b900463ffffffff1684615ae3565b6120649190615b02565b905083156122745760095460405163461fc8a560e11b815260016004820152612710916001600160a01b031690638c3f914a90602401602060405180830381865afa1580156120b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120db91906158ce565b6120e6906002615ae3565b6120f2906127106158e7565b61225d600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216c9190615b16565b61217790600a615c1d565b6121a27f0000000000000000000000000000000000000000000000000000000000000000600a615c1d565b6121ac9190615ae3565b600954604051631bbc615960e11b815260016004820181905260248201526001600160a01b0390911690633778c2b290604401602060405180830381865afa1580156121fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222091906158ce565b61224b7f0000000000000000000000000000000000000000000000000000000000000000600a615c1d565b6122559190615ae3565b859190614cc2565b6122679190615ae3565b6122719190615b02565b90505b9392505050565b600854600090610100900460ff1615806123a65750600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612307919061579c565b612312906003615876565b600860029054906101000a90046001600160a01b03166001600160a01b031663d266f5d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612365573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612389919061579c565b61239391906158a4565b65ffffffffffff164265ffffffffffff16115b156123c4576040516316b0245b60e21b815260040160405180910390fd5b6002546001146124035760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b6044820152606401610f28565b600280556001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116908516036126a957600954604051632ce91b7360e11b8152600060048201526001600160a01b03909116906359d236e690602401602060405180830381865afa158015612483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a7919061572e565b6124c457604051631c184ff560e01b815260040160405180910390fd5b6124ce8484612cb3565b9050818110156124f557808260405163c2d2c74360e01b8152600401610f28929190615828565b612500600082614d6f565b61250a6000614e26565b61253f6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308661507a565b600b5460405163557856ad60e11b81526001600160a01b039091169063aaf0ad5a906125719030908790600401615c2c565b600060405180830381600087803b15801561258b57600080fd5b505af115801561259f573d6000803e3d6000fd5b5050600a54604051632f42aef560e01b81526001600160a01b039091169250632f42aef591506125f79033907f0000000000000000000000000000000000000000000000000000000000000000908690600401615c45565b600060405180830381600087803b15801561261157600080fd5b505af1158015612625573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316600080516020615f97833981519152858460405161269c929190615828565b60405180910390a36128de565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316036128c557600954604051632ce91b7360e11b8152600160048201526001600160a01b03909116906359d236e690602401602060405180830381865afa15801561272b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274f919061572e565b61276c57604051631c184ff560e01b815260040160405180910390fd5b6127768484612cb3565b90508181101561279d57808260405163c2d2c74360e01b8152600401610f28929190615828565b6127a8600182614d6f565b6127b26001614e26565b600a546127ee906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116913391168661507a565b600b54604051633a56e30760e01b81526001600160a01b0390911690633a56e307906128209033908590600401615c2c565b600060405180830381600087803b15801561283a57600080fd5b505af115801561284e573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316600080516020615f97833981519152858460405161269c929190615828565b60405163042a67ad60e41b815260040160405180910390fd5b60016002559392505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c59061292e9084903390600401615717565b600060405180830381600087803b15801561294857600080fd5b505af115801561295c573d6000803e3d6000fd5b5050505061271063ffffffff168263ffffffff1611806129825750606463ffffffff8316105b156129a05760405163042a67ad60e41b815260040160405180910390fd5b6007805463ffffffff191663ffffffff84161790556040517f5760955ed2acbd2b290c0a6edf1c0bc845f64f1da0b9f89582fac3daade8dff59061065a9084906156da565b600854610100900460ff161580612b0d5750600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6e919061579c565b612a79906003615876565b600860029054906101000a90046001600160a01b03166001600160a01b031663d266f5d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af0919061579c565b612afa91906158a4565b65ffffffffffff164265ffffffffffff16115b15612b2b576040516316b0245b60e21b815260040160405180910390fd5b60015460405163d09a20c560e01b81527037b832b930ba37b92fb932b837b93a32b960791b916001600160a01b03169063d09a20c590612b719084903390600401615717565b600060405180830381600087803b158015612b8b57600080fd5b505af1158015612b9f573d6000803e3d6000fd5b505060095460405163622f48eb60e11b8152600160048201526001600160a01b03909116925063c45e91d69150602401602060405180830381865afa158015612bec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1091906158ce565b8303612c2b57612c21600183614d6f565b612c2b6001614e26565b60095460405163622f48eb60e11b8152600060048201526001600160a01b039091169063c45e91d690602401602060405180830381865afa158015612c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9891906158ce565b8303610ef657612ca9600083614d6f565b610ef66000614e26565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603612ee157600954604051631bbc615960e11b81526001600482015260006024820181905291612e4b916001600160a01b0390911690633778c2b290604401602060405180830381865afa158015612d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6991906158ce565b612d947f0000000000000000000000000000000000000000000000000000000000000000600a615c1d565b612d9e9190615ae3565b600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e159190615b16565b612e2090600a615c1d565b61224b7f0000000000000000000000000000000000000000000000000000000000000000600a615c1d565b60095460405163bf30142b60e01b8152600060048201529192506001600160a01b03169063bf30142b906024015b602060405180830381865afa158015612e96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eba91906158ce565b811115612eda57604051632c05036160e01b815260040160405180910390fd5b9050612fa4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316036128c5576000612f72600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612148573d6000803e3d6000fd5b60095460405163bf30142b60e01b8152600160048201529192506001600160a01b03169063bf30142b90602401612e79565b92915050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590612fee9084903390600401615717565b600060405180830381600087803b15801561300857600080fd5b505af115801561301c573d6000803e3d6000fd5b50505050610a4b826137c8565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c59061306d9084903390600401615717565b600060405180830381600087803b15801561308757600080fd5b505af115801561309b573d6000803e3d6000fd5b5050505062093a808463ffffffff1611806130be5750620151808463ffffffff16105b156130dc5760405163042a67ad60e41b815260040160405180910390fd5b61271063ffffffff841610156131055760405163042a67ad60e41b815260040160405180910390fd5b610e1063ffffffff8316108061312657508363ffffffff168263ffffffff16115b156131445760405163042a67ad60e41b815260040160405180910390fd5b60078054600160201b600160601b031916600160201b63ffffffff8781169190910263ffffffff60401b191691909117600160401b868316021763ffffffff60601b1916600160601b918516919091021790556040517f6627cd780fa2d7faf558f4d9d700a0852b79903fd60ce8c0f734103cf8aa12b890610e0690869086908690615808565b6131d4816137c8565b801561344a576005805463ffffffff19169055600754600160e01b900463ffffffff166001600160401b0381111561320e5761320e6157f2565b604051908082528060200260200182016040528015613237578160200160208202803683370190505b50805161324c91600691602090910190615262565b5060058054600160201b600160701b031916600160201b4265ffffffffffff1602179055600061327c6001611fa0565b600b54604051630664aecb60e41b81529192506000916001600160a01b039091169063664aecb0906132b2903090600401615383565b602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f391906158ce565b90508181101561336d57600b546001600160a01b031663359fe780306133198486615c69565b6040518363ffffffff1660e01b8152600401613336929190615c2c565b600060405180830381600087803b15801561335057600080fd5b505af1158015613364573d6000803e3d6000fd5b505050506133e1565b818111156133e157600b546001600160a01b0316631b0a68f2306133918585615c69565b6040518363ffffffff1660e01b81526004016133ae929190615c2c565b600060405180830381600087803b1580156133c857600080fd5b505af11580156133dc573d6000803e3d6000fd5b505050505b60095460405162d1673960e01b815260016004820152602481018490526001600160a01b039091169062d16739906044015b600060405180830381600087803b15801561342d57600080fd5b505af1158015613441573d6000803e3d6000fd5b50505050505050565b6003805463ffffffff19169055600754600160e01b900463ffffffff166001600160401b0381111561347e5761347e6157f2565b6040519080825280602002602001820160405280156134a7578160200160208202803683370190505b5080516134bc91600491602090910190615262565b5060038054600160201b600160701b031916600160201b4265ffffffffffff160217905560006134eb81611fa0565b600a54604051635f0736a160e01b81523060048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015292935060009290911690635f0736a190604401602060405180830381865afa158015613561573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358591906158ce565b90508181101561362157600a546001600160a01b031663e6eb207a307f00000000000000000000000000000000000000000000000000000000000000006135cc8587615c69565b6040518463ffffffff1660e01b81526004016135ea93929190615c45565b600060405180830381600087803b15801561360457600080fd5b505af1158015613618573d6000803e3d6000fd5b505050506136b7565b818111156136b757600a546001600160a01b0316638b7f3fb9307f00000000000000000000000000000000000000000000000000000000000000006136668686615c69565b6040518463ffffffff1660e01b815260040161368493929190615c45565b600060405180830381600087803b15801561369e57600080fd5b505af11580156136b2573d6000803e3d6000fd5b505050505b60095460405162d1673960e01b815260006004820152602481018490526001600160a01b039091169062d1673990604401613413565b6000600860029054906101000a90046001600160a01b03166001600160a01b031663b5e713056040518163ffffffff1660e01b8152600401602060405180830381865afa158015613742573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376691906158ce565b60095460405163ae7e8d8160e01b8152600481018390529192506001600160a01b03169063ae7e8d8190602401600060405180830381600087803b1580156137ad57600080fd5b505af11580156137c1573d6000803e3d6000fd5b5050505050565b60095460405163622f48eb60e11b815282151560048201526000916001600160a01b03169063c45e91d690602401602060405180830381865afa158015613813573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061383791906158ce565b600c546040516304ea0e8b60e31b8152600481018390529192506001600160a01b031690632750745890602401602060405180830381865afa158015613881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a5919061572e565b15610a4b57600c5460405163ae41809560e01b8152600481018390526001600160a01b039091169063ae41809590602401600060405180830381600087803b1580156138f057600080fd5b505af1158015613904573d6000803e3d6000fd5b5050600954604051631f2b4c9d60e11b81526001600160a01b039091169250633e56993a9150610af290859060001990600090600401615c80565b6000600860029054906101000a90046001600160a01b03166001600160a01b031663b5e713056040518163ffffffff1660e01b8152600401602060405180830381865afa158015613994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b891906158ce565b90506000600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a3391906158ce565b600754604080516080810182526003805463ffffffff818116845265ffffffffffff600160201b830416602080860191909152600160501b90920481168486015260048054865181850281018501909752808752979850600160e01b909604169560009593949293606086019392909190830182828015613af357602002820191906000526020600020906000905b825461010083900a900460ff161515815260206001928301818104948501949093039092029101808411613ac25790505b5050505050815250509050838310613bb7578060600151816040015163ffffffff1681518110613b2557613b25615860565b6020026020010151613bb25760408101516004805460019263ffffffff16908110613b5257613b52615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556003805463ffffffff1691613b9283615c98565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b613c65565b8060600151816040015163ffffffff1681518110613bd757613bd7615860565b602002602001015115613c655760408101516004805460009263ffffffff16908110613c0557613c05615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556003805463ffffffff1691613c4583615cbb565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b8181604001516001613c779190615cdb565b613c819190615cfa565b6003805463ffffffff60501b1916600160501b63ffffffff93841681029190911790915560408051608081018252600580548086168352600160201b810465ffffffffffff16602080850191909152949004909416818301526006805483518186028101860190945280845291949360608601939290830182828015613d4657602002820191906000526020600020906000905b825461010083900a900460ff161515815260206001928301818104948501949093039092029101808411613d155790505b5050505050815250509050838311613e0a578060600151816040015163ffffffff1681518110613d7857613d78615860565b6020026020010151613e055760408101516006805460019263ffffffff16908110613da557613da5615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556005805463ffffffff1691613de583615c98565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b613eb8565b8060600151816040015163ffffffff1681518110613e2a57613e2a615860565b602002602001015115613eb85760408101516006805460009263ffffffff16908110613e5857613e58615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556005805463ffffffff1691613e9883615cbb565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b8181604001516001613eca9190615cdb565b613ed49190615cfa565b6005805463ffffffff92909216600160501b0263ffffffff60501b1990921691909117905550505050565b6009546040805163e97206a960e01b815290516000926001600160a01b03169163e97206a9916004808301926102009291908290030181865afa158015613f4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f6e9190615a52565b905081156145255760408101515151600090613f8990615191565b90506000613f98600283615d1d565b613fe27f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000615d55565b613fec9190615d96565b9050600082600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140689190615b16565b6140729190615d55565b61407d90600a615c1d565b90506000837f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006140cf866024615d96565b6140d99190615d96565b6140e39190615d55565b6140ed9190615d55565b6140f890600a615c1d565b9050600061417f8284600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614154573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417891906158ce565b9190614cc2565b60408701515151909150600090614197908486614cc2565b604080516101008101825260075463ffffffff808216808452600160201b83048216602080860191909152600160401b8404831685870152600160601b840483166060860152600160801b840483166080860152600160a01b8404831660a0860152600160c01b8404831660c0860152600160e01b909304821660e0850152918c0151909301519394509092600092614235929061271090614cc216565b905060006040518061018001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600d60009054906101000a90046001600160a01b03166001600160a01b03168152602001600015158152602001838152602001868152602001858152602001846040015163ffffffff168152602001600065ffffffffffff168152602001846020015163ffffffff164261431791906158e7565b65ffffffffffff168152602001846060015163ffffffff1681526020018960000b81525090506000600c60009054906101000a90046001600160a01b03166001600160a01b03166353c7f8e0836040516020016143749190615dd9565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161439f9190615ed5565b6020604051808303816000875af11580156143be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143e291906158ce565b600d54600c5460408051639787d10760e01b815290519394506001600160a01b03928316936398fc55d89390921691639787d107916004808201926020929091908290030181865afa15801561443c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144609190615f08565b836040518363ffffffff1660e01b815260040161447e929190615c2c565b600060405180830381600087803b15801561449857600080fd5b505af11580156144ac573d6000803e3d6000fd5b5050600954604051631f2b4c9d60e11b81526001600160a01b039091169250633e56993a91506144e59060019085908890600401615c80565b600060405180830381600087803b1580156144ff57600080fd5b505af1158015614513573d6000803e3d6000fd5b50505050505050505050505050505050565b6000600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561457a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061459e9190615b16565b604083015160200151519091506000906145b9836002615f25565b6145c490600a615c1d565b6145ce9190615b02565b90506000600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614625573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061464991906158ce565b614654846002615f25565b61465f90600a615c1d565b6146699190615b02565b9050600061467683615191565b90506000614685600283615d1d565b6146cf7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000615d55565b6146d99190615d96565b905060006146e78387615d55565b6146f290600a615c1d565b90506000837f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000614744866024615d96565b61474e9190615d96565b6147589190615d55565b6147629190615d55565b61476d90600a615c1d565b9050600061477c868385614cc2565b9050600061478b888486614cc2565b604080516101008101825260075463ffffffff808216808452600160201b830482166020850152600160401b8304821684860152600160601b830482166060850152600160801b830482166080850152600160a01b8304821660a0850152600160c01b8304821660c0850152600160e01b909204811660e08401528e51909301519394509092600092614823929061271090614cc216565b905060006040518061018001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600d60009054906101000a90046001600160a01b03166001600160a01b03168152602001600015158152602001838152602001868152602001858152602001846040015163ffffffff168152602001600065ffffffffffff168152602001846020015163ffffffff164261490591906158e7565b65ffffffffffff168152602001846060015163ffffffff1681526020018960000b81525090506000600c60009054906101000a90046001600160a01b03166001600160a01b03166353c7f8e0836040516020016149629190615dd9565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161498d9190615ed5565b6020604051808303816000875af11580156149ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149d091906158ce565b600d54600c5460408051639787d10760e01b815290519394506001600160a01b03928316936398fc55d89390921691639787d107916004808201926020929091908290030181865afa158015614a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a4e9190615f08565b836040518363ffffffff1660e01b8152600401614a6c929190615c2c565b600060405180830381600087803b158015614a8657600080fd5b505af1158015614a9a573d6000803e3d6000fd5b5050600954604051631f2b4c9d60e11b81526001600160a01b039091169250633e56993a9150614ad39060009085908890600401615c80565b600060405180830381600087803b158015614aed57600080fd5b505af1158015614b01573d6000803e3d6000fd5b50505050505050505050505050505050505050565b60008054604051632d37002d60e21b815282916001600160a01b03169063b4dc00b490614b47908690600401615f46565b602060405180830381865afa158015614b64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b889190615f08565b90506001600160a01b038116612fa45782604051635c3fa9cd60e01b8152600401610f289190615f46565b600080846001600160a01b031663095ea7b360e01b8585604051602401614bdb929190615c2c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614c199190615f5b565b6000604051808303816000865af19150503d8060008114614c56576040519150601f19603f3d011682016040523d82523d6000602084013e614c5b565b606091505b5091509150818015614c85575080511580614c85575080806020019051810190614c85919061572e565b6137c15760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610f28565b6000808060001985870985870292508281108382030391505080600003614cfb5760008411614cf057600080fd5b508290049050612274565b808411614d0757600080fd5b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b60095460405163bf30142b60e01b8152831515600482015260009183916001600160a01b039091169063bf30142b90602401602060405180830381865afa158015614dbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614de291906158ce565b614dec9190615c69565b6009546040516336cd4d3160e11b81528515156004820152602481018390529192506001600160a01b031690636d9a9a6290604401613413565b600954604051632ce91b7360e11b815282151560048201526000916001600160a01b0316906359d236e690602401602060405180830381865afa158015614e71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e95919061572e565b60095460405163622f48eb60e11b815284151560048201529192506000916001600160a01b039091169063c45e91d690602401602060405180830381865afa158015614ee5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f0991906158ce565b905081158061506c5750818015614f885750600c546040516304ea0e8b60e31b8152600481018390526001600160a01b0390911690632750745890602401602060405180830381865afa158015614f64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f88919061572e565b801561506c5750600c546040516307018e9b60e21b8152600481018390526001600160a01b0390911690631c063a6c90602401602060405180830381865afa158015614fd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ffc91906158ce565b60095460405163bf30142b60e01b815285151560048201526001600160a01b039091169063bf30142b90602401602060405180830381865afa158015615046573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061506a91906158ce565b105b15610ef657610ef6836137c8565b600080856001600160a01b03166323b872dd60e01b8686866040516024016150a493929190615c45565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516150e29190615f5b565b6000604051808303816000865af19150503d806000811461511f576040519150601f19603f3d011682016040523d82523d6000602084013e615124565b606091505b509150915081801561514e57508051158061514e57508080602001905181019061514e919061572e565b610b205760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610f28565b6000805b600a83106151bc576151a8600a84615b02565b9250806151b481615f77565b915050615195565b600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561520f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152339190615b16565b6122749082615d55565b6040518060400160405280615250615307565b815260200161525d615307565b905290565b82805482825590600052602060002090601f016020900481019282156152f75791602002820160005b838211156152c857835183826101000a81548160ff021916908315150217905550926020019260010160208160000104928301926001030261528b565b80156152f55782816101000a81549060ff02191690556001016020816000010492830192600103026152c8565b505b5061530392915061532d565b5090565b604080516080810182526000808252602082018190529181019190915260608082015290565b5b80821115615303576000815560010161532e565b803563ffffffff8116811461535657600080fd5b919050565b60006020828403121561536d57600080fd5b61227482615342565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610fe957600080fd5b600080604083850312156153bf57600080fd5b82356153ca81615397565b915060208301356153da81615397565b809150509250929050565b60006080830163ffffffff808451168552602065ffffffffffff818601511681870152816040860151166040870152606085015191506080606087015282825180855260a0880191508284019450600093505b8084101561545a57845115158252938201936001939093019290820190615438565b509695505050505050565b60208152600082516040602084015261548160608401826153e5565b90506020840151601f1984830301604085015261549e82826153e5565b95945050505050565b8015158114610fe957600080fd5b6000602082840312156154c757600080fd5b8135612274816154a7565b6000602082840312156154e457600080fd5b5035919050565b60008060006060848603121561550057600080fd5b61550984615342565b925061551760208501615342565b915061552560408501615342565b90509250925092565b6000806040838503121561554157600080fd5b50508035926020909101359150565b60006020828403121561556257600080fd5b813561227481615397565b602080825282518282018190526000919060409081850190868401855b828110156155c357815180516001600160d81b03191685528601516001600160e01b03191686850152928401929085019060010161558a565b5091979650505050505050565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401528060a08501511660a08401525060c083015161563860c084018263ffffffff169052565b5060e083015161565060e084018263ffffffff169052565b5092915050565b6020808252825182820181905260009190848201906040850190845b818110156156995783516001600160d81b03191683529284019291840191600101615673565b50909695505050505050565b6000806000606084860312156156ba57600080fd5b83356156c581615397565b95602085013595506040909401359392505050565b63ffffffff91909116815260200190565b600080604083850312156156fe57600080fd5b823561570981615397565b946020939093013593505050565b9182526001600160a01b0316602082015260400190565b60006020828403121561574057600080fd5b8151612274816154a7565b634e487b7160e01b600052601160045260246000fd5b600063ffffffff8381169083168181101561577e5761577e61574b565b039392505050565b805165ffffffffffff8116811461535657600080fd5b6000602082840312156157ae57600080fd5b61227482615786565b634e487b7160e01b600052601260045260246000fd5b600065ffffffffffff808416806157e6576157e66157b7565b92169190910492915050565b634e487b7160e01b600052604160045260246000fd5b63ffffffff93841681529183166020830152909116604082015260600190565b918252602082015260400190565b60006020828403121561584857600080fd5b81516001600160d81b03198116811461227457600080fd5b634e487b7160e01b600052603260045260246000fd5b600065ffffffffffff8083168185168183048111821515161561589b5761589b61574b565b02949350505050565b600065ffffffffffff8083168185168083038211156158c5576158c561574b565b01949350505050565b6000602082840312156158e057600080fd5b5051919050565b600082198211156158fa576158fa61574b565b500190565b600060a0828403121561591157600080fd5b60405160a081016001600160401b038111828210171561594157634e487b7160e01b600052604160045260246000fd5b80604052508091508251615954816154a7565b815261596260208401615786565b60208201526040830151604082015260608301516060820152608083015160808201525092915050565b60006020828403121561599e57600080fd5b604051602081016001600160401b03811182821017156159ce57634e487b7160e01b600052604160045260246000fd5b6040529151825250919050565b6000606082840312156159ed57600080fd5b604051606081016001600160401b0381118282101715615a1d57634e487b7160e01b600052604160045260246000fd5b604052905080615a2d848461598c565b8152615a3c846020850161598c565b6020820152604083015160408201525092915050565b60006102008284031215615a6557600080fd5b604051608081016001600160401b0381118282101715615a9557634e487b7160e01b600052604160045260246000fd5b604052615aa284846158ff565b8152615ab18460a085016158ff565b6020820152615ac48461014085016159db565b6040820152615ad7846101a085016159db565b60608201529392505050565b6000816000190483118215151615615afd57615afd61574b565b500290565b600082615b1157615b116157b7565b500490565b600060208284031215615b2857600080fd5b815160ff8116811461227457600080fd5b600181815b80851115615b74578160001904821115615b5a57615b5a61574b565b80851615615b6757918102915b93841c9390800290615b3e565b509250929050565b600082615b8b57506001612fa4565b81615b9857506000612fa4565b8160018114615bae5760028114615bb857615bd4565b6001915050612fa4565b60ff841115615bc957615bc961574b565b50506001821b612fa4565b5060208310610133831016604e8410600b8410161715615bf7575081810a612fa4565b615c018383615b39565b8060001904821115615c1557615c1561574b565b029392505050565b600061227460ff841683615b7c565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082821015615c7b57615c7b61574b565b500390565b92151583526020830191909152604082015260600190565b600063ffffffff808316818103615cb157615cb161574b565b6001019392505050565b600063ffffffff821680615cd157615cd161574b565b6000190192915050565b600063ffffffff8083168185168083038211156158c5576158c561574b565b600063ffffffff80841680615d1157615d116157b7565b92169190910692915050565b60008160000b8360000b80615d3457615d346157b7565b607f19821460001982141615615d4c57615d4c61574b565b90059392505050565b600081810b83820b8281128015607f19830184121615615d7757615d7761574b565b81607f018313811615615d8c57615d8c61574b565b5090039392505050565b60008160000b8360000b6000821282607f03821381151615615dba57615dba61574b565b82607f19038212811615615dd057615dd061574b565b50019392505050565b600061018082019050615ded828451615376565b6020830151615dff6020840182615376565b506040830151615e126040840182615376565b506060830151615e26606084018215159052565b506080830151608083015260a083015160a083015260c083015160c083015260e0830151615e5c60e084018263ffffffff169052565b506101008381015165ffffffffffff9081169184019190915261012080850151909116908301526101408084015163ffffffff16908301526101609283015160000b929091019190915290565b60005b83811015615ec4578181015183820152602001615eac565b83811115611c1e5750506000910152565b6020815260008251806020840152615ef4816040850160208701615ea9565b601f01601f19169190910160400192915050565b600060208284031215615f1a57600080fd5b815161227481615397565b600060ff821660ff84168160ff0481118215151615615c1557615c1561574b565b6001600160d81b031991909116815260200190565b60008251615f6d818460208701615ea9565b9190910192915050565b60008160000b607f8103615f8d57615f8d61574b565b6001019291505056fefa2dda1cc1b86e41239702756b13effbc1a092b5c57e3ad320fbe4f3b13fe235a264697066735822122003ea6394fa64b8bff1f488d4be6aba8a8c2e92bd11e3f96363605607804d441964736f6c634300080f00330000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b000000000000000000000000007f7a1cb838a872515c8ebd16be4b14ef43a222000000000000000000000000bf2b6e99b0e8d4c96b946c182132f5752eaa55c600000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d50000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000000c03000000000000000000000000000000000000000000000000000000000003f48000000000000000000000000000000000000000000000000000000000000186a0000000000000000000000000000000000000000000000000000000000000384000000000000000000000000000000000000000000000000000000000000003b6000000000000000000000000000000000000000000000000000000000007e90000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000015
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101a15760003560e01c806301de9ba8146101a657806302b1d239146101bb57806302fb0c5e146101f8578063083b27321461021a5780630f15f4c01461022d578063158ef93e1461023557806319f63dd714610242578063200d2ed21461025557806322f3e2d41461026a5780632ecd1f201461027257806333bd33b4146102855780633a3f54bc1461029857806341f19a46146102ab5780634657b36c146102be57806351b42b00146102d15780635924be70146102d95780635ec2c7bf146102ee5780636e703c2e146103015780637159a6181461033a57806379502c55146103425780638129fc1c14610414578063923cb9521461041c5780639459b8751461042f5780639e897711146104445780639f1d0f5914610465578063aa9760a114610478578063ab1047711461048b578063aea564af1461049e578063bb2eb4d2146104c5578063ca706bcf146104da578063cd3293de146104ed578063d4aae0c414610514578063dd0081c714610527578063f2f6d5bb14610530578063f2fa473714610543575b600080fd5b6101b96101b436600461535b565b610556565b005b6101e27f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d581565b6040516101ef9190615383565b60405180910390f35b60085461020a90610100900460ff1681565b60405190151581526020016101ef565b600d546101e2906001600160a01b031681565b6101b9610666565b60085461020a9060ff1681565b6101b96102503660046153ac565b6106ee565b61025d6107ce565b6040516101ef9190615465565b61020a610956565b6101b96102803660046154b5565b6109cd565b6101b96102933660046154d2565b610a4f565b6101b96102a63660046154eb565b610b28565b6101b96102b936600461552e565b610e14565b6101b96102cc366004615550565b610efb565b6101b9610f53565b6102e1610fec565b6040516101ef919061556d565b600c546101e2906001600160a01b031681565b6103287f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff90911681526020016101ef565b6101b961158f565b6104076040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915250604080516101008101825260075463ffffffff8082168352600160201b820481166020840152600160401b8204811693830193909352600160601b810483166060830152600160801b810483166080830152600160a01b8104831660a0830152600160c01b8104831660c0830152600160e01b900490911660e082015290565b6040516101ef91906155d0565b6101b9611c24565b6001546101e2906001600160a01b031681565b610437611ced565b6040516101ef9190615657565b6104576104523660046154b5565b611fa0565b6040519081526020016101ef565b6104576104733660046156a5565b61227b565b6101b961048636600461535b565b6128ea565b6101b961049936600461552e565b6129e5565b6103287f000000000000000000000000000000000000000000000000000000000000000981565b6104cd606481565b6040516101ef91906156da565b6104576104e83660046156eb565b612cb3565b6101e27f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f81565b6000546101e2906001600160a01b031681565b6104cd61271081565b6101b961053e3660046154b5565b612faa565b6101b96105513660046154eb565b613029565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c59061059a9084903390600401615717565b600060405180830381600087803b1580156105b457600080fd5b505af11580156105c8573d6000803e3d6000fd5b5050505061271063ffffffff168263ffffffff1611806105ee5750606463ffffffff8316105b1561060c5760405163042a67ad60e41b815260040160405180910390fd5b6007805463ffffffff60801b1916600160801b63ffffffff8516021790556040517fb3f67f3c41e3a7c2c87b93a1c1fe4581744242b44b44d4a873ca8facec1ee8a59061065a9084906156da565b60405180910390a15050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c5906106aa9084903390600401615717565b600060405180830381600087803b1580156106c457600080fd5b505af11580156106d8573d6000803e3d6000fd5b50506008805461ff001916610100179055505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c5906107329084903390600401615717565b600060405180830381600087803b15801561074c57600080fd5b505af1158015610760573d6000803e3d6000fd5b505050506001600160a01b038316158061078157506001600160a01b038216155b1561079f5760405163042a67ad60e41b815260040160405180910390fd5b50600c80546001600160a01b039384166001600160a01b031991821617909155600d8054929093169116179055565b6107d661523d565b6040805160c0810182526003805463ffffffff80821684860190815265ffffffffffff600160201b8404166060860152600160501b909204166080840152600480548551602082810282018101909752818152949593948694869360a0870193909183018282801561088757602002820191906000526020600020906000905b825461010083900a900460ff1615158152602060019283018181049485019490930390920291018084116108565790505b5050509190925250505081526040805160808101825260028401805463ffffffff808216845265ffffffffffff600160201b830416602085810191909152600160501b9092041683850152600386018054855181840281018401909652808652958201959394929360608601939283018282801561094457602002820191906000526020600020906000905b825461010083900a900460ff1615158152602060019283018181049485019490930390920291018084116109135790505b50505050508152505081525050905090565b6000805460405163e52223bb60e01b81526001600160a01b039091169063e52223bb90610987903090600401615383565b602060405180830381865afa1580156109a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c8919061572e565b905090565b60015460405163d09a20c560e01b81526d37b832b930ba37b92fb0b236b4b760911b916001600160a01b03169063d09a20c590610a109084903390600401615717565b600060405180830381600087803b158015610a2a57600080fd5b505af1158015610a3e573d6000803e3d6000fd5b50505050610a4b826131cb565b5050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610a939084903390600401615717565b600060405180830381600087803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b5050600954604051630cef4ced60e21b8152600481018690526001600160a01b0390911692506333bd33b491506024015b600060405180830381600087803b158015610b0c57600080fd5b505af1158015610b20573d6000803e3d6000fd5b505050505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610b6c9084903390600401615717565b600060405180830381600087803b158015610b8657600080fd5b505af1158015610b9a573d6000803e3d6000fd5b50505050610e108463ffffffff161080610bbf57508163ffffffff168363ffffffff16115b80610bce575063ffffffff8216155b80610bdd575063ffffffff8316155b80610c845750610bed8383615761565b63ffffffff16600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6a919061579c565b610c7a9063ffffffff87166157cd565b65ffffffffffff16105b15610ca25760405163042a67ad60e41b815260040160405180910390fd5b60078054600160a01b600160e01b031916600160a01b63ffffffff8781169190910263ffffffff60c01b191691909117600160c01b86831602176001600160e01b0316600160e01b918516918202179091556005805463ffffffff63ffffffff60501b01191690556001600160401b03811115610d2157610d216157f2565b604051908082528060200260200182016040528015610d4a578160200160208202803683370190505b508051610d5f91600691602090910190615262565b506003805463ffffffff63ffffffff60501b011916905563ffffffff82166001600160401b03811115610d9457610d946157f2565b604051908082528060200260200182016040528015610dbd578160200160208202803683370190505b508051610dd291600491602090910190615262565b507f9f11b1d829316eb1d4d6f91541c83d9f78bc1e309f755c759d190c973f7b4fae848484604051610e0693929190615808565b60405180910390a150505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610e589084903390600401615717565b600060405180830381600087803b158015610e7257600080fd5b505af1158015610e86573d6000803e3d6000fd5b50506009546040516320f8cd2360e11b81526001600160a01b0390911692506341f19a469150610ebc9086908690600401615828565b600060405180830381600087803b158015610ed657600080fd5b505af1158015610eea573d6000803e3d6000fd5b50505050610ef66136ed565b505050565b6000546001600160a01b03163314610f31573360405163053e900f60e21b8152600401610f289190615383565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590610f979084903390600401615717565b600060405180830381600087803b158015610fb157600080fd5b505af1158015610fc5573d6000803e3d6000fd5b50506008805461ff001916905550610fdf905060016137c8565b610fe960006137c8565b50565b60606000600960009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611043573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110679190615836565b90506000600a60009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e29190615836565b90506000600b60009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115d9190615836565b60408051600d8082526101c08201909252919250816020015b6040805180820190915260008082526020820152815260200190600190039081611176575050604080518082019091526001600160d81b0319851681526336cd4d3160e11b602082015281519195509085906000906111d7576111d7615860565b60200260200101819052506040518060400160405280846001600160d81b0319168152602001633e56993a60e01b6001600160e01b0319168152508460018151811061122557611225615860565b60200260200101819052506040518060400160405280846001600160d81b031916815260200163ae7e8d8160e01b6001600160e01b0319168152508460028151811061127357611273615860565b60200260200101819052506040518060400160405280846001600160d81b031916815260200162d1673960e01b6001600160e01b031916815250846003815181106112c0576112c0615860565b60200260200101819052506040518060400160405280846001600160d81b03191681526020016341f19a4660e01b6001600160e01b0319168152508460048151811061130e5761130e615860565b60200260200101819052506040518060400160405280846001600160d81b03191681526020016333bd33b460e01b6001600160e01b0319168152508460058151811061135c5761135c615860565b60200260200101819052506040518060400160405280836001600160d81b0319168152602001632f42aef560e01b6001600160e01b031916815250846006815181106113aa576113aa615860565b60200260200101819052506040518060400160405280836001600160d81b031916815260200163e6eb207a60e01b6001600160e01b031916815250846007815181106113f8576113f8615860565b60200260200101819052506040518060400160405280836001600160d81b0319168152602001638b7f3fb960e01b6001600160e01b0319168152508460088151811061144657611446615860565b60200260200101819052506040518060400160405280826001600160d81b0319168152602001633a56e30760e01b6001600160e01b0319168152508460098151811061149457611494615860565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163aaf0ad5a60e01b6001600160e01b03191681525084600a815181106114e2576114e2615860565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163359fe78060e01b6001600160e01b03191681525084600b8151811061153057611530615860565b60200260200101819052506040518060400160405280826001600160d81b0319168152602001631b0a68f260e01b6001600160e01b03191681525084600c8151811061157e5761157e615860565b602002602001018190525050505090565b600854610100900460ff1615806116b75750600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611618919061579c565b611623906003615876565b600860029054906101000a90046001600160a01b03166001600160a01b031663d266f5d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611676573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169a919061579c565b6116a491906158a4565b65ffffffffffff164265ffffffffffff16115b156116d5576040516316b0245b60e21b815260040160405180910390fd5b60015460405163d09a20c560e01b81526f6f70657261746f725f6f70657261746560801b916001600160a01b03169063d09a20c59061171a9084903390600401615717565b600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b505060085460ff169150611771905057604051633cb84dd760e11b815260040160405180910390fd5b6117796136ed565b61178161393f565b604080516101008101825260075463ffffffff8082168352600160201b820481166020840152600160401b8204811683850152600160601b820481166060840152600160801b820481166080840152600160a01b8204811660a08401819052600160c01b8304821660c0850152600160e01b9092041660e0830152600954925163734f9e2760e11b815260016004820152919290916001600160a01b039091169063e69f3c4e90602401602060405180830381865afa158015611848573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186c91906158ce565b61187691906158e7565b4265ffffffffffff161015801561189d575060c081015160055463ffffffff918216911610155b156118ac576118ac60016131cb565b60a081015160095460405163734f9e2760e11b81526000600482015263ffffffff909216916001600160a01b039091169063e69f3c4e90602401602060405180830381865afa158015611903573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192791906158ce565b61193191906158e7565b4265ffffffffffff1610158015611958575060c081015160035463ffffffff918216911610155b156119675761196760006131cb565b6009546040805163e97206a960e01b815290516000926001600160a01b03169163e97206a9916004808301926102009291908290030181865afa1580156119b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d69190615a52565b90506000600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5191906158ce565b82515190915015611b3c57600c548251608001516040516304ea0e8b60e31b81526001600160a01b0390921691632750745891611a949160040190815260200190565b602060405180830381865afa158015611ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad5919061572e565b15611b0d5760408201516020015151811180611af957506060820151602001515181105b15611b0857611b0860006137c8565b611b3c565b6040820151602001515181108015611b2d57506060820151602001515181115b15611b3c57611b3c6000613eff565b60208201515115611c1e57600c546020830151608001516040516304ea0e8b60e31b81526001600160a01b0390921691632750745891611b829160040190815260200190565b602060405180830381865afa158015611b9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc3919061572e565b15611bf55760408201515151811080611be157506060820151515181115b15611bf057611bf060016137c8565b611c1e565b6040820151515181118015611c0f57506060820151515181105b15611c1e57611c1e6001613eff565b50505050565b60015460405163d09a20c560e01b81526d37b832b930ba37b92fb0b236b4b760911b916001600160a01b03169063d09a20c590611c679084903390600401615717565b600060405180830381600087803b158015611c8157600080fd5b505af1158015611c95573d6000803e3d6000fd5b505060085460ff16159150611cbf9050576040516358b8d27560e01b815260040160405180910390fd5b611cc76136ed565b611cd160016131cb565b611cdb60006131cb565b506008805461ffff1916610101179055565b60408051600580825260c082019092526060916020820160a08036833701905050905064505249434560d81b81600081518110611d2c57611d2c615860565b6001600160d81b031990921660209283029190910190910152611d546452414e474560d81b90565b81600181518110611d6757611d67615860565b6001600160d81b031990921660209283029190910190910152611d8f64545253525960d81b90565b81600281518110611da257611da2615860565b6001600160d81b031990921660209283029190910190910152611dca6426a4a72a2960d91b90565b81600381518110611ddd57611ddd615860565b6001600160d81b031990921660209283029190910190910152611e0564524f4c455360d81b90565b81600481518110611e1857611e18615860565b60200260200101906001600160d81b03191690816001600160d81b03191681525050611e5d81600081518110611e5057611e50615860565b6020026020010151614b16565b600860026101000a8154816001600160a01b0302191690836001600160a01b03160217905550611e9981600181518110611e5057611e50615860565b600960006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611ed581600281518110611e5057611e50615860565b600a60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611f1181600381518110611e5057611e50615860565b600b60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611f4d81600481518110611e5057611e50615860565b600180546001600160a01b0319166001600160a01b03928316179055600b54611f9d917f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d581169116600019614bb3565b90565b600a546040516305489ad560e21b815260009182916001600160a01b03909116906315226b5490611ff5907f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f90600401615383565b602060405180830381865afa158015612012573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203691906158ce565b6007549091506000906127109061205a90600160801b900463ffffffff1684615ae3565b6120649190615b02565b905083156122745760095460405163461fc8a560e11b815260016004820152612710916001600160a01b031690638c3f914a90602401602060405180830381865afa1580156120b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120db91906158ce565b6120e6906002615ae3565b6120f2906127106158e7565b61225d600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216c9190615b16565b61217790600a615c1d565b6121a27f0000000000000000000000000000000000000000000000000000000000000009600a615c1d565b6121ac9190615ae3565b600954604051631bbc615960e11b815260016004820181905260248201526001600160a01b0390911690633778c2b290604401602060405180830381865afa1580156121fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222091906158ce565b61224b7f0000000000000000000000000000000000000000000000000000000000000012600a615c1d565b6122559190615ae3565b859190614cc2565b6122679190615ae3565b6122719190615b02565b90505b9392505050565b600854600090610100900460ff1615806123a65750600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612307919061579c565b612312906003615876565b600860029054906101000a90046001600160a01b03166001600160a01b031663d266f5d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612365573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612389919061579c565b61239391906158a4565b65ffffffffffff164265ffffffffffff16115b156123c4576040516316b0245b60e21b815260040160405180910390fd5b6002546001146124035760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b6044820152606401610f28565b600280556001600160a01b037f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d58116908516036126a957600954604051632ce91b7360e11b8152600060048201526001600160a01b03909116906359d236e690602401602060405180830381865afa158015612483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a7919061572e565b6124c457604051631c184ff560e01b815260040160405180910390fd5b6124ce8484612cb3565b9050818110156124f557808260405163c2d2c74360e01b8152600401610f28929190615828565b612500600082614d6f565b61250a6000614e26565b61253f6001600160a01b037f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d51633308661507a565b600b5460405163557856ad60e11b81526001600160a01b039091169063aaf0ad5a906125719030908790600401615c2c565b600060405180830381600087803b15801561258b57600080fd5b505af115801561259f573d6000803e3d6000fd5b5050600a54604051632f42aef560e01b81526001600160a01b039091169250632f42aef591506125f79033907f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f908690600401615c45565b600060405180830381600087803b15801561261157600080fd5b505af1158015612625573d6000803e3d6000fd5b505050507f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b03167f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d56001600160a01b0316600080516020615f97833981519152858460405161269c929190615828565b60405180910390a36128de565b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b0316846001600160a01b0316036128c557600954604051632ce91b7360e11b8152600160048201526001600160a01b03909116906359d236e690602401602060405180830381865afa15801561272b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274f919061572e565b61276c57604051631c184ff560e01b815260040160405180910390fd5b6127768484612cb3565b90508181101561279d57808260405163c2d2c74360e01b8152600401610f28929190615828565b6127a8600182614d6f565b6127b26001614e26565b600a546127ee906001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f8116913391168661507a565b600b54604051633a56e30760e01b81526001600160a01b0390911690633a56e307906128209033908590600401615c2c565b600060405180830381600087803b15801561283a57600080fd5b505af115801561284e573d6000803e3d6000fd5b505050507f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d56001600160a01b03167f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b0316600080516020615f97833981519152858460405161269c929190615828565b60405163042a67ad60e41b815260040160405180910390fd5b60016002559392505050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c59061292e9084903390600401615717565b600060405180830381600087803b15801561294857600080fd5b505af115801561295c573d6000803e3d6000fd5b5050505061271063ffffffff168263ffffffff1611806129825750606463ffffffff8316105b156129a05760405163042a67ad60e41b815260040160405180910390fd5b6007805463ffffffff191663ffffffff84161790556040517f5760955ed2acbd2b290c0a6edf1c0bc845f64f1da0b9f89582fac3daade8dff59061065a9084906156da565b600854610100900460ff161580612b0d5750600860029054906101000a90046001600160a01b03166001600160a01b0316637321f1006040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6e919061579c565b612a79906003615876565b600860029054906101000a90046001600160a01b03166001600160a01b031663d266f5d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af0919061579c565b612afa91906158a4565b65ffffffffffff164265ffffffffffff16115b15612b2b576040516316b0245b60e21b815260040160405180910390fd5b60015460405163d09a20c560e01b81527037b832b930ba37b92fb932b837b93a32b960791b916001600160a01b03169063d09a20c590612b719084903390600401615717565b600060405180830381600087803b158015612b8b57600080fd5b505af1158015612b9f573d6000803e3d6000fd5b505060095460405163622f48eb60e11b8152600160048201526001600160a01b03909116925063c45e91d69150602401602060405180830381865afa158015612bec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1091906158ce565b8303612c2b57612c21600183614d6f565b612c2b6001614e26565b60095460405163622f48eb60e11b8152600060048201526001600160a01b039091169063c45e91d690602401602060405180830381865afa158015612c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9891906158ce565b8303610ef657612ca9600083614d6f565b610ef66000614e26565b60007f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d56001600160a01b0316836001600160a01b031603612ee157600954604051631bbc615960e11b81526001600482015260006024820181905291612e4b916001600160a01b0390911690633778c2b290604401602060405180830381865afa158015612d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6991906158ce565b612d947f0000000000000000000000000000000000000000000000000000000000000012600a615c1d565b612d9e9190615ae3565b600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e159190615b16565b612e2090600a615c1d565b61224b7f0000000000000000000000000000000000000000000000000000000000000009600a615c1d565b60095460405163bf30142b60e01b8152600060048201529192506001600160a01b03169063bf30142b906024015b602060405180830381865afa158015612e96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eba91906158ce565b811115612eda57604051632c05036160e01b815260040160405180910390fd5b9050612fa4565b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b0316836001600160a01b0316036128c5576000612f72600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612148573d6000803e3d6000fd5b60095460405163bf30142b60e01b8152600160048201529192506001600160a01b03169063bf30142b90602401612e79565b92915050565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c590612fee9084903390600401615717565b600060405180830381600087803b15801561300857600080fd5b505af115801561301c573d6000803e3d6000fd5b50505050610a4b826137c8565b60015460405163d09a20c560e01b81526e6f70657261746f725f706f6c69637960881b916001600160a01b03169063d09a20c59061306d9084903390600401615717565b600060405180830381600087803b15801561308757600080fd5b505af115801561309b573d6000803e3d6000fd5b5050505062093a808463ffffffff1611806130be5750620151808463ffffffff16105b156130dc5760405163042a67ad60e41b815260040160405180910390fd5b61271063ffffffff841610156131055760405163042a67ad60e41b815260040160405180910390fd5b610e1063ffffffff8316108061312657508363ffffffff168263ffffffff16115b156131445760405163042a67ad60e41b815260040160405180910390fd5b60078054600160201b600160601b031916600160201b63ffffffff8781169190910263ffffffff60401b191691909117600160401b868316021763ffffffff60601b1916600160601b918516919091021790556040517f6627cd780fa2d7faf558f4d9d700a0852b79903fd60ce8c0f734103cf8aa12b890610e0690869086908690615808565b6131d4816137c8565b801561344a576005805463ffffffff19169055600754600160e01b900463ffffffff166001600160401b0381111561320e5761320e6157f2565b604051908082528060200260200182016040528015613237578160200160208202803683370190505b50805161324c91600691602090910190615262565b5060058054600160201b600160701b031916600160201b4265ffffffffffff1602179055600061327c6001611fa0565b600b54604051630664aecb60e41b81529192506000916001600160a01b039091169063664aecb0906132b2903090600401615383565b602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f391906158ce565b90508181101561336d57600b546001600160a01b031663359fe780306133198486615c69565b6040518363ffffffff1660e01b8152600401613336929190615c2c565b600060405180830381600087803b15801561335057600080fd5b505af1158015613364573d6000803e3d6000fd5b505050506133e1565b818111156133e157600b546001600160a01b0316631b0a68f2306133918585615c69565b6040518363ffffffff1660e01b81526004016133ae929190615c2c565b600060405180830381600087803b1580156133c857600080fd5b505af11580156133dc573d6000803e3d6000fd5b505050505b60095460405162d1673960e01b815260016004820152602481018490526001600160a01b039091169062d16739906044015b600060405180830381600087803b15801561342d57600080fd5b505af1158015613441573d6000803e3d6000fd5b50505050505050565b6003805463ffffffff19169055600754600160e01b900463ffffffff166001600160401b0381111561347e5761347e6157f2565b6040519080825280602002602001820160405280156134a7578160200160208202803683370190505b5080516134bc91600491602090910190615262565b5060038054600160201b600160701b031916600160201b4265ffffffffffff160217905560006134eb81611fa0565b600a54604051635f0736a160e01b81523060048201526001600160a01b037f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f8116602483015292935060009290911690635f0736a190604401602060405180830381865afa158015613561573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358591906158ce565b90508181101561362157600a546001600160a01b031663e6eb207a307f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6135cc8587615c69565b6040518463ffffffff1660e01b81526004016135ea93929190615c45565b600060405180830381600087803b15801561360457600080fd5b505af1158015613618573d6000803e3d6000fd5b505050506136b7565b818111156136b757600a546001600160a01b0316638b7f3fb9307f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6136668686615c69565b6040518463ffffffff1660e01b815260040161368493929190615c45565b600060405180830381600087803b15801561369e57600080fd5b505af11580156136b2573d6000803e3d6000fd5b505050505b60095460405162d1673960e01b815260006004820152602481018490526001600160a01b039091169062d1673990604401613413565b6000600860029054906101000a90046001600160a01b03166001600160a01b031663b5e713056040518163ffffffff1660e01b8152600401602060405180830381865afa158015613742573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376691906158ce565b60095460405163ae7e8d8160e01b8152600481018390529192506001600160a01b03169063ae7e8d8190602401600060405180830381600087803b1580156137ad57600080fd5b505af11580156137c1573d6000803e3d6000fd5b5050505050565b60095460405163622f48eb60e11b815282151560048201526000916001600160a01b03169063c45e91d690602401602060405180830381865afa158015613813573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061383791906158ce565b600c546040516304ea0e8b60e31b8152600481018390529192506001600160a01b031690632750745890602401602060405180830381865afa158015613881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a5919061572e565b15610a4b57600c5460405163ae41809560e01b8152600481018390526001600160a01b039091169063ae41809590602401600060405180830381600087803b1580156138f057600080fd5b505af1158015613904573d6000803e3d6000fd5b5050600954604051631f2b4c9d60e11b81526001600160a01b039091169250633e56993a9150610af290859060001990600090600401615c80565b6000600860029054906101000a90046001600160a01b03166001600160a01b031663b5e713056040518163ffffffff1660e01b8152600401602060405180830381865afa158015613994573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b891906158ce565b90506000600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a3391906158ce565b600754604080516080810182526003805463ffffffff818116845265ffffffffffff600160201b830416602080860191909152600160501b90920481168486015260048054865181850281018501909752808752979850600160e01b909604169560009593949293606086019392909190830182828015613af357602002820191906000526020600020906000905b825461010083900a900460ff161515815260206001928301818104948501949093039092029101808411613ac25790505b5050505050815250509050838310613bb7578060600151816040015163ffffffff1681518110613b2557613b25615860565b6020026020010151613bb25760408101516004805460019263ffffffff16908110613b5257613b52615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556003805463ffffffff1691613b9283615c98565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b613c65565b8060600151816040015163ffffffff1681518110613bd757613bd7615860565b602002602001015115613c655760408101516004805460009263ffffffff16908110613c0557613c05615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556003805463ffffffff1691613c4583615cbb565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b8181604001516001613c779190615cdb565b613c819190615cfa565b6003805463ffffffff60501b1916600160501b63ffffffff93841681029190911790915560408051608081018252600580548086168352600160201b810465ffffffffffff16602080850191909152949004909416818301526006805483518186028101860190945280845291949360608601939290830182828015613d4657602002820191906000526020600020906000905b825461010083900a900460ff161515815260206001928301818104948501949093039092029101808411613d155790505b5050505050815250509050838311613e0a578060600151816040015163ffffffff1681518110613d7857613d78615860565b6020026020010151613e055760408101516006805460019263ffffffff16908110613da557613da5615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556005805463ffffffff1691613de583615c98565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b613eb8565b8060600151816040015163ffffffff1681518110613e2a57613e2a615860565b602002602001015115613eb85760408101516006805460009263ffffffff16908110613e5857613e58615860565b60009182526020808320908204018054931515601f9092166101000a91820260ff90920219909316179091556005805463ffffffff1691613e9883615cbb565b91906101000a81548163ffffffff021916908363ffffffff160217905550505b8181604001516001613eca9190615cdb565b613ed49190615cfa565b6005805463ffffffff92909216600160501b0263ffffffff60501b1990921691909117905550505050565b6009546040805163e97206a960e01b815290516000926001600160a01b03169163e97206a9916004808301926102009291908290030181865afa158015613f4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f6e9190615a52565b905081156145255760408101515151600090613f8990615191565b90506000613f98600283615d1d565b613fe27f00000000000000000000000000000000000000000000000000000000000000127f0000000000000000000000000000000000000000000000000000000000000009615d55565b613fec9190615d96565b9050600082600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140689190615b16565b6140729190615d55565b61407d90600a615c1d565b90506000837f00000000000000000000000000000000000000000000000000000000000000097f00000000000000000000000000000000000000000000000000000000000000126140cf866024615d96565b6140d99190615d96565b6140e39190615d55565b6140ed9190615d55565b6140f890600a615c1d565b9050600061417f8284600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614154573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417891906158ce565b9190614cc2565b60408701515151909150600090614197908486614cc2565b604080516101008101825260075463ffffffff808216808452600160201b83048216602080860191909152600160401b8404831685870152600160601b840483166060860152600160801b840483166080860152600160a01b8404831660a0860152600160c01b8404831660c0860152600160e01b909304821660e0850152918c0151909301519394509092600092614235929061271090614cc216565b905060006040518061018001604052807f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d56001600160a01b031681526020017f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b03168152602001600d60009054906101000a90046001600160a01b03166001600160a01b03168152602001600015158152602001838152602001868152602001858152602001846040015163ffffffff168152602001600065ffffffffffff168152602001846020015163ffffffff164261431791906158e7565b65ffffffffffff168152602001846060015163ffffffff1681526020018960000b81525090506000600c60009054906101000a90046001600160a01b03166001600160a01b03166353c7f8e0836040516020016143749190615dd9565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161439f9190615ed5565b6020604051808303816000875af11580156143be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143e291906158ce565b600d54600c5460408051639787d10760e01b815290519394506001600160a01b03928316936398fc55d89390921691639787d107916004808201926020929091908290030181865afa15801561443c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144609190615f08565b836040518363ffffffff1660e01b815260040161447e929190615c2c565b600060405180830381600087803b15801561449857600080fd5b505af11580156144ac573d6000803e3d6000fd5b5050600954604051631f2b4c9d60e11b81526001600160a01b039091169250633e56993a91506144e59060019085908890600401615c80565b600060405180830381600087803b1580156144ff57600080fd5b505af1158015614513573d6000803e3d6000fd5b50505050505050505050505050505050565b6000600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561457a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061459e9190615b16565b604083015160200151519091506000906145b9836002615f25565b6145c490600a615c1d565b6145ce9190615b02565b90506000600860029054906101000a90046001600160a01b03166001600160a01b031663d8cf24fd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614625573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061464991906158ce565b614654846002615f25565b61465f90600a615c1d565b6146699190615b02565b9050600061467683615191565b90506000614685600283615d1d565b6146cf7f00000000000000000000000000000000000000000000000000000000000000097f0000000000000000000000000000000000000000000000000000000000000012615d55565b6146d99190615d96565b905060006146e78387615d55565b6146f290600a615c1d565b90506000837f00000000000000000000000000000000000000000000000000000000000000127f0000000000000000000000000000000000000000000000000000000000000009614744866024615d96565b61474e9190615d96565b6147589190615d55565b6147629190615d55565b61476d90600a615c1d565b9050600061477c868385614cc2565b9050600061478b888486614cc2565b604080516101008101825260075463ffffffff808216808452600160201b830482166020850152600160401b8304821684860152600160601b830482166060850152600160801b830482166080850152600160a01b8304821660a0850152600160c01b8304821660c0850152600160e01b909204811660e08401528e51909301519394509092600092614823929061271090614cc216565b905060006040518061018001604052807f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b031681526020017f00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d56001600160a01b03168152602001600d60009054906101000a90046001600160a01b03166001600160a01b03168152602001600015158152602001838152602001868152602001858152602001846040015163ffffffff168152602001600065ffffffffffff168152602001846020015163ffffffff164261490591906158e7565b65ffffffffffff168152602001846060015163ffffffff1681526020018960000b81525090506000600c60009054906101000a90046001600160a01b03166001600160a01b03166353c7f8e0836040516020016149629190615dd9565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161498d9190615ed5565b6020604051808303816000875af11580156149ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149d091906158ce565b600d54600c5460408051639787d10760e01b815290519394506001600160a01b03928316936398fc55d89390921691639787d107916004808201926020929091908290030181865afa158015614a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a4e9190615f08565b836040518363ffffffff1660e01b8152600401614a6c929190615c2c565b600060405180830381600087803b158015614a8657600080fd5b505af1158015614a9a573d6000803e3d6000fd5b5050600954604051631f2b4c9d60e11b81526001600160a01b039091169250633e56993a9150614ad39060009085908890600401615c80565b600060405180830381600087803b158015614aed57600080fd5b505af1158015614b01573d6000803e3d6000fd5b50505050505050505050505050505050505050565b60008054604051632d37002d60e21b815282916001600160a01b03169063b4dc00b490614b47908690600401615f46565b602060405180830381865afa158015614b64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b889190615f08565b90506001600160a01b038116612fa45782604051635c3fa9cd60e01b8152600401610f289190615f46565b600080846001600160a01b031663095ea7b360e01b8585604051602401614bdb929190615c2c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614c199190615f5b565b6000604051808303816000865af19150503d8060008114614c56576040519150601f19603f3d011682016040523d82523d6000602084013e614c5b565b606091505b5091509150818015614c85575080511580614c85575080806020019051810190614c85919061572e565b6137c15760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610f28565b6000808060001985870985870292508281108382030391505080600003614cfb5760008411614cf057600080fd5b508290049050612274565b808411614d0757600080fd5b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b60095460405163bf30142b60e01b8152831515600482015260009183916001600160a01b039091169063bf30142b90602401602060405180830381865afa158015614dbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614de291906158ce565b614dec9190615c69565b6009546040516336cd4d3160e11b81528515156004820152602481018390529192506001600160a01b031690636d9a9a6290604401613413565b600954604051632ce91b7360e11b815282151560048201526000916001600160a01b0316906359d236e690602401602060405180830381865afa158015614e71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e95919061572e565b60095460405163622f48eb60e11b815284151560048201529192506000916001600160a01b039091169063c45e91d690602401602060405180830381865afa158015614ee5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f0991906158ce565b905081158061506c5750818015614f885750600c546040516304ea0e8b60e31b8152600481018390526001600160a01b0390911690632750745890602401602060405180830381865afa158015614f64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f88919061572e565b801561506c5750600c546040516307018e9b60e21b8152600481018390526001600160a01b0390911690631c063a6c90602401602060405180830381865afa158015614fd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ffc91906158ce565b60095460405163bf30142b60e01b815285151560048201526001600160a01b039091169063bf30142b90602401602060405180830381865afa158015615046573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061506a91906158ce565b105b15610ef657610ef6836137c8565b600080856001600160a01b03166323b872dd60e01b8686866040516024016150a493929190615c45565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516150e29190615f5b565b6000604051808303816000865af19150503d806000811461511f576040519150601f19603f3d011682016040523d82523d6000602084013e615124565b606091505b509150915081801561514e57508051158061514e57508080602001905181019061514e919061572e565b610b205760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610f28565b6000805b600a83106151bc576151a8600a84615b02565b9250806151b481615f77565b915050615195565b600860029054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561520f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152339190615b16565b6122749082615d55565b6040518060400160405280615250615307565b815260200161525d615307565b905290565b82805482825590600052602060002090601f016020900481019282156152f75791602002820160005b838211156152c857835183826101000a81548160ff021916908315150217905550926020019260010160208160000104928301926001030261528b565b80156152f55782816101000a81549060ff02191690556001016020816000010492830192600103026152c8565b505b5061530392915061532d565b5090565b604080516080810182526000808252602082018190529181019190915260608082015290565b5b80821115615303576000815560010161532e565b803563ffffffff8116811461535657600080fd5b919050565b60006020828403121561536d57600080fd5b61227482615342565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610fe957600080fd5b600080604083850312156153bf57600080fd5b82356153ca81615397565b915060208301356153da81615397565b809150509250929050565b60006080830163ffffffff808451168552602065ffffffffffff818601511681870152816040860151166040870152606085015191506080606087015282825180855260a0880191508284019450600093505b8084101561545a57845115158252938201936001939093019290820190615438565b509695505050505050565b60208152600082516040602084015261548160608401826153e5565b90506020840151601f1984830301604085015261549e82826153e5565b95945050505050565b8015158114610fe957600080fd5b6000602082840312156154c757600080fd5b8135612274816154a7565b6000602082840312156154e457600080fd5b5035919050565b60008060006060848603121561550057600080fd5b61550984615342565b925061551760208501615342565b915061552560408501615342565b90509250925092565b6000806040838503121561554157600080fd5b50508035926020909101359150565b60006020828403121561556257600080fd5b813561227481615397565b602080825282518282018190526000919060409081850190868401855b828110156155c357815180516001600160d81b03191685528601516001600160e01b03191686850152928401929085019060010161558a565b5091979650505050505050565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401528060a08501511660a08401525060c083015161563860c084018263ffffffff169052565b5060e083015161565060e084018263ffffffff169052565b5092915050565b6020808252825182820181905260009190848201906040850190845b818110156156995783516001600160d81b03191683529284019291840191600101615673565b50909695505050505050565b6000806000606084860312156156ba57600080fd5b83356156c581615397565b95602085013595506040909401359392505050565b63ffffffff91909116815260200190565b600080604083850312156156fe57600080fd5b823561570981615397565b946020939093013593505050565b9182526001600160a01b0316602082015260400190565b60006020828403121561574057600080fd5b8151612274816154a7565b634e487b7160e01b600052601160045260246000fd5b600063ffffffff8381169083168181101561577e5761577e61574b565b039392505050565b805165ffffffffffff8116811461535657600080fd5b6000602082840312156157ae57600080fd5b61227482615786565b634e487b7160e01b600052601260045260246000fd5b600065ffffffffffff808416806157e6576157e66157b7565b92169190910492915050565b634e487b7160e01b600052604160045260246000fd5b63ffffffff93841681529183166020830152909116604082015260600190565b918252602082015260400190565b60006020828403121561584857600080fd5b81516001600160d81b03198116811461227457600080fd5b634e487b7160e01b600052603260045260246000fd5b600065ffffffffffff8083168185168183048111821515161561589b5761589b61574b565b02949350505050565b600065ffffffffffff8083168185168083038211156158c5576158c561574b565b01949350505050565b6000602082840312156158e057600080fd5b5051919050565b600082198211156158fa576158fa61574b565b500190565b600060a0828403121561591157600080fd5b60405160a081016001600160401b038111828210171561594157634e487b7160e01b600052604160045260246000fd5b80604052508091508251615954816154a7565b815261596260208401615786565b60208201526040830151604082015260608301516060820152608083015160808201525092915050565b60006020828403121561599e57600080fd5b604051602081016001600160401b03811182821017156159ce57634e487b7160e01b600052604160045260246000fd5b6040529151825250919050565b6000606082840312156159ed57600080fd5b604051606081016001600160401b0381118282101715615a1d57634e487b7160e01b600052604160045260246000fd5b604052905080615a2d848461598c565b8152615a3c846020850161598c565b6020820152604083015160408201525092915050565b60006102008284031215615a6557600080fd5b604051608081016001600160401b0381118282101715615a9557634e487b7160e01b600052604160045260246000fd5b604052615aa284846158ff565b8152615ab18460a085016158ff565b6020820152615ac48461014085016159db565b6040820152615ad7846101a085016159db565b60608201529392505050565b6000816000190483118215151615615afd57615afd61574b565b500290565b600082615b1157615b116157b7565b500490565b600060208284031215615b2857600080fd5b815160ff8116811461227457600080fd5b600181815b80851115615b74578160001904821115615b5a57615b5a61574b565b80851615615b6757918102915b93841c9390800290615b3e565b509250929050565b600082615b8b57506001612fa4565b81615b9857506000612fa4565b8160018114615bae5760028114615bb857615bd4565b6001915050612fa4565b60ff841115615bc957615bc961574b565b50506001821b612fa4565b5060208310610133831016604e8410600b8410161715615bf7575081810a612fa4565b615c018383615b39565b8060001904821115615c1557615c1561574b565b029392505050565b600061227460ff841683615b7c565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082821015615c7b57615c7b61574b565b500390565b92151583526020830191909152604082015260600190565b600063ffffffff808316818103615cb157615cb161574b565b6001019392505050565b600063ffffffff821680615cd157615cd161574b565b6000190192915050565b600063ffffffff8083168185168083038211156158c5576158c561574b565b600063ffffffff80841680615d1157615d116157b7565b92169190910692915050565b60008160000b8360000b80615d3457615d346157b7565b607f19821460001982141615615d4c57615d4c61574b565b90059392505050565b600081810b83820b8281128015607f19830184121615615d7757615d7761574b565b81607f018313811615615d8c57615d8c61574b565b5090039392505050565b60008160000b8360000b6000821282607f03821381151615615dba57615dba61574b565b82607f19038212811615615dd057615dd061574b565b50019392505050565b600061018082019050615ded828451615376565b6020830151615dff6020840182615376565b506040830151615e126040840182615376565b506060830151615e26606084018215159052565b506080830151608083015260a083015160a083015260c083015160c083015260e0830151615e5c60e084018263ffffffff169052565b506101008381015165ffffffffffff9081169184019190915261012080850151909116908301526101408084015163ffffffff16908301526101609283015160000b929091019190915290565b60005b83811015615ec4578181015183820152602001615eac565b83811115611c1e5750506000910152565b6020815260008251806020840152615ef4816040850160208701615ea9565b601f01601f19169190910160400192915050565b600060208284031215615f1a57600080fd5b815161227481615397565b600060ff821660ff84168160ff0481118215151615615c1557615c1561574b565b6001600160d81b031991909116815260200190565b60008251615f6d818460208701615ea9565b9190910192915050565b60008160000b607f8103615f8d57615f8d61574b565b6001019291505056fefa2dda1cc1b86e41239702756b13effbc1a092b5c57e3ad320fbe4f3b13fe235a264697066735822122003ea6394fa64b8bff1f488d4be6aba8a8c2e92bd11e3f96363605607804d441964736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b000000000000000000000000007f7a1cb838a872515c8ebd16be4b14ef43a222000000000000000000000000bf2b6e99b0e8d4c96b946c182132f5752eaa55c600000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d50000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000000c03000000000000000000000000000000000000000000000000000000000003f48000000000000000000000000000000000000000000000000000000000000186a0000000000000000000000000000000000000000000000000000000000000384000000000000000000000000000000000000000000000000000000000000003b6000000000000000000000000000000000000000000000000000000000007e90000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000015
-----Decoded View---------------
Arg [0] : kernel_ (address): 0x2286d7f9639e8158FaD1169e76d1FbC38247f54b
Arg [1] : auctioneer_ (address): 0x007F7A1cb838A872515c8ebd16bE4b14Ef43a222
Arg [2] : callback_ (address): 0xbf2B6E99B0E8D4c96b946c182132f5752eAa55C6
Arg [3] : tokens_ (address[2]): 0x64aa3364F17a4D01c6f1751Fd97C2BD3D7e7f1D5,0x6B175474E89094C44Da98b954EedeAC495271d0F
Arg [4] : configParams (uint32[8]): 3075,259200,100000,14400,950,518400,18,21
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 0000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b
Arg [1] : 000000000000000000000000007f7a1cb838a872515c8ebd16be4b14ef43a222
Arg [2] : 000000000000000000000000bf2b6e99b0e8d4c96b946c182132f5752eaa55c6
Arg [3] : 00000000000000000000000064aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d5
Arg [4] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000c03
Arg [6] : 000000000000000000000000000000000000000000000000000000000003f480
Arg [7] : 00000000000000000000000000000000000000000000000000000000000186a0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000003840
Arg [9] : 00000000000000000000000000000000000000000000000000000000000003b6
Arg [10] : 000000000000000000000000000000000000000000000000000000000007e900
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000015
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.