Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Inflation
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- Verified at
- 2022-07-13T21:12:48.307080Z
Constructor Arguments
0000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b0000000000000000000000000000000000000000000000000000000062d1b8d6
Arg [0] (address) : 0x4598a6c05910ab914f0cbaaca1911cd337d10d29
Arg [1] (address) : 0x1000000000000000000000000000000000000002
Arg [2] (address) : 0xbaf89d873d198ff78e72d2745b01cba3c6e5be6b
Arg [3] (uint256) : 1657911510
./contracts/inflation/implementation/Inflation.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../../genesis/implementation/FlareDaemon.sol"; import "../../genesis/interface/IFlareDaemonize.sol"; import "../../genesis/interface/IInflationGenesis.sol"; import "../../utils/implementation/GovernedAndFlareDaemonized.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../lib/InflationAnnum.sol"; import "../lib/InflationAnnums.sol"; import "../interface/IIInflationAllocation.sol"; import "../lib/RewardService.sol"; import "../interface/IISupply.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; /** * @title Inflation * @notice A contract to manage the process of recognizing, authorizing, minting, and funding * native tokens for Flare services that are rewardable by inflation. * @dev Please see docs/specs/Inflation.md to better understand this terminology. **/ contract Inflation is IInflationGenesis, GovernedAndFlareDaemonized, IFlareDaemonize, AddressUpdatable { using InflationAnnums for InflationAnnums.InflationAnnumsState; using SafeMath for uint256; using SafePct for uint256; // Composable contracts IIInflationAllocation public inflationAllocation; IISupply public supply; // The annums InflationAnnums.InflationAnnumsState private inflationAnnums; // Inflation annum data // Instance vars uint256 public lastAuthorizationTs; // The last time inflation was authorized mapping(IIInflationReceiver => TopupConfiguration) internal topupConfigurations; // A topup configuration for a contract // receiving inflation. uint256 public totalSelfDestructReceivedWei; uint256 immutable public rewardEpochStartTs; // Do not start inflation annums before this uint256 public rewardEpochStartedTs; // When the first reward epoch was started // Constants string internal constant ERR_IS_ZERO = "address is 0"; string internal constant ERR_OUT_OF_BALANCE = "out of balance"; string internal constant ERR_TOPUP_LOW = "topup low"; string internal constant ERR_GET_ANNUAL_PERCENT = "unknown error. getAnnualPercentageBips"; string internal constant ERR_SUPPLY_UPDATE = "unknown error. updateAuthorizedInflationAndCirculatingSupply"; string internal constant ERR_REQUEST_MINT = "unknown error. requestMinting"; uint256 internal constant BIPS100 = 1e4; // 100% in basis points uint256 internal constant DEFAULT_TOPUP_FACTOR_X100 = 120; // DO NOT UPDATE - this affects supply contract, which is expected to be updated once a day uint256 internal constant AUTHORIZE_TIME_FRAME_SEC = 1 days; event InflationAuthorized(uint256 amountWei); event MintingReceived(uint256 amountWei, uint256 selfDestructAmountWei); event TopupRequested(uint256 amountWei); event InflationAllocationSet(IIInflationAllocation inflationAllocation); event RewardServiceTopupComputed(IIInflationReceiver inflationReceiver, uint256 amountWei); event RewardServiceDailyAuthorizedInflationComputed(IIInflationReceiver inflationReceiver, uint256 amountWei); event RewardServiceTopupRequestReceived(IIInflationReceiver inflationReceiver, uint256 amountWei); event SupplySet(IISupply oldSupply, IISupply newSupply); event TopupConfigurationSet(TopupConfiguration topupConfiguration); event NewAnnumInitialized( uint256 startTimeStamp, uint256 endTimeStamp, uint256 inflatableSupplyWei, uint256 recognizedInflationWei, uint256 totalAuthorizedInflationWei, uint256 totalInflationTopupRequestedWei, uint256 totalInflationTopupReceivedWei, uint256 totalInflationTopupWithdrawnWei ); /** * @dev This modifier ensures that this contract's balance matches the expected balance. */ modifier mustBalance { _; require (getExpectedBalance() == address(this).balance, ERR_OUT_OF_BALANCE); } modifier notZero(address _address) { require(_address != address(0), ERR_IS_ZERO); _; } constructor ( address _governance, FlareDaemon _flareDaemon, address _addressUpdater, uint256 _rewardEpochStartTs ) GovernedAndFlareDaemonized(_governance, _flareDaemon) AddressUpdatable(_addressUpdater) { rewardEpochStartTs = _rewardEpochStartTs; } /** * @notice Get a tuple of totals across inflation annums. * @return _totalAuthorizedInflationWei Total inflation authorized to be mintable * @return _totalInflationTopupRequestedWei Total inflation requested to be topped up for rewarding * @return _totalInflationTopupReceivedWei Total inflation received for funding reward services * @return _totalInflationTopupWithdrawnWei Total inflation used for funding reward services * @return _totalRecognizedInflationWei Total inflation recognized for rewarding * @return _totalSelfDestructReceivedWei Total balance received as a self-destruct recipient */ function getTotals() external view returns ( uint256 _totalAuthorizedInflationWei, uint256 _totalInflationTopupRequestedWei, uint256 _totalInflationTopupReceivedWei, uint256 _totalInflationTopupWithdrawnWei, uint256 _totalRecognizedInflationWei, uint256 _totalSelfDestructReceivedWei ) { _totalAuthorizedInflationWei = inflationAnnums.totalAuthorizedInflationWei; _totalInflationTopupRequestedWei = inflationAnnums.totalInflationTopupRequestedWei; _totalInflationTopupReceivedWei = inflationAnnums.totalInflationTopupReceivedWei; _totalInflationTopupWithdrawnWei = inflationAnnums.totalInflationTopupWithdrawnWei; _totalRecognizedInflationWei = inflationAnnums.totalRecognizedInflationWei; _totalSelfDestructReceivedWei = totalSelfDestructReceivedWei; } /** * @notice Given an index, return the annum at that index. * @param _index The index of the annum to fetch. * @return The inflation annum state. * @dev Expect library to revert if index not found. */ function getAnnum(uint256 _index) external view returns(InflationAnnum.InflationAnnumState memory) { return inflationAnnums.getAnnum(_index); } /** * @notice Return the current annum. * @return The inflation annum state of the current annum. * @dev Expect library to revert if there is no current annum. */ function getCurrentAnnum() external view returns(InflationAnnum.InflationAnnumState memory) { return inflationAnnums.getCurrentAnnum(); } /** * @notice Receive newly minted native tokens from the FlareDaemon. * @dev Assume that the amount received will be >= last topup requested across all services. * If there is not enough balance sent to cover the topup request, expect library method will revert. * Also assume that any balance received greater than the topup request calculated * came from self-destructor sending a balance to this contract. */ function receiveMinting() external override payable onlyFlareDaemon mustBalance { uint256 amountPostedWei = inflationAnnums.receiveTopupRequest(); // Assume that if we received (or already have) more than we posted, // it must be amounts sent from a contract self-destruct // recipient in this block. uint256 prevBalance = getExpectedBalance(); uint256 selfDestructProceeds = address(this).balance.sub(prevBalance); if (selfDestructProceeds > 0) { totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructProceeds); } emit MintingReceived(amountPostedWei, selfDestructProceeds); } /** * @notice Set the topup configuration for a reward service. * @param _inflationReceiver The reward service to receive the inflation funds for distribution. * @param _topupType The type to signal how the topup amounts are to be calculated. * FACTOROFDAILYAUTHORIZED = Use a factor of last daily authorized to set a * target balance for a reward service to maintain as a reserve for claiming. * ALLAUTHORIZED = Mint enough native tokens to topup reward service contract to hold * all authorized but unrequested rewards. * @param _topupFactorX100 If _topupType == FACTOROFDAILYAUTHORIZED, then this factor (times 100) * is multipled by last daily authorized inflation to obtain the * maximum balance that a reward service can hold at any given time. If it holds less, * then this max amount is used to compute the mint request topup required to * bring the reward service contract native token balance up to that amount. * @dev Topup factor, if _topupType == FACTOROFDAILYAUTHORIZED, must be greater than 100. */ function setTopupConfiguration( IIInflationReceiver _inflationReceiver, TopupType _topupType, uint256 _topupFactorX100 ) external notZero(address(_inflationReceiver)) onlyGovernance { if (_topupType == TopupType.FACTOROFDAILYAUTHORIZED) { require(_topupFactorX100 > 100, ERR_TOPUP_LOW); } TopupConfiguration storage topupConfiguration = topupConfigurations[_inflationReceiver]; topupConfiguration.topupType = _topupType; topupConfiguration.topupFactorX100 = _topupFactorX100; topupConfiguration.configured = true; emit TopupConfigurationSet(topupConfiguration); } /** * @notice Given an inflation receiver, get the topup configuration. * @param _inflationReceiver The reward service. * @return _topupConfiguration The configurartion of how the topup requests are calculated for a given * reward service. */ function getTopupConfiguration( IIInflationReceiver _inflationReceiver ) external notZero(address(_inflationReceiver)) returns(TopupConfiguration memory _topupConfiguration) { TopupConfiguration storage topupConfiguration = topupConfigurations[_inflationReceiver]; if (!topupConfiguration.configured) { topupConfiguration.topupType = TopupType.FACTOROFDAILYAUTHORIZED; topupConfiguration.topupFactorX100 = DEFAULT_TOPUP_FACTOR_X100; topupConfiguration.configured = true; } _topupConfiguration.topupType = topupConfiguration.topupType; _topupConfiguration.topupFactorX100 = topupConfiguration.topupFactorX100; _topupConfiguration.configured = topupConfiguration.configured; } /** * @notice Pulsed by the FlareDaemon to trigger timing-based events for the inflation process. * @dev There are two events: * 1) an annual event to recognize inflation for a new annum * 2) a daily event to: * a) authorize mintable inflation for rewarding * b) request minting of enough native tokens to topup reward services for claiming reserves */ function daemonize() external virtual override notZero(address(supply)) onlyFlareDaemon returns(bool) { // If inflation rewarding not started yet, blow off processing until it does. if (block.timestamp < rewardEpochStartTs) { return true; } // If inflation rewarding started and we have not updated when it started, do so now. if (rewardEpochStartedTs == 0) { rewardEpochStartedTs = block.timestamp; } // Is it time to recognize an initial inflation annum? if (inflationAnnums.getCount() == 0) { _initNewAnnum(block.timestamp); } else { uint256 currentAnnumEndTimeStamp = inflationAnnums.getCurrentAnnum().endTimeStamp; // Is it time to recognize a new inflation annum? if (block.timestamp > currentAnnumEndTimeStamp) { _initNewAnnum(currentAnnumEndTimeStamp.add(1)); } } // Is it time to authorize new inflation? Do it daily. if (lastAuthorizationTs.add(AUTHORIZE_TIME_FRAME_SEC) <= block.timestamp) { // Update time we last authorized. lastAuthorizationTs = block.timestamp; // Authorize inflation for current sharing percentges. uint256 amountAuthorizedWei = inflationAnnums.authorizeDailyInflation( block.timestamp, inflationAllocation.getSharingPercentages() ); emit InflationAuthorized(amountAuthorizedWei); // Call supply contract to keep inflatable balance and circulating supply updated. try supply.updateAuthorizedInflationAndCirculatingSupply(amountAuthorizedWei) { } catch Error(string memory message) { revert(message); } catch { revert(ERR_SUPPLY_UPDATE); } // Time to compute topup amount for inflation receivers. uint256 topupRequestWei = inflationAnnums.computeTopupRequest(this); emit TopupRequested(topupRequestWei); // Send mint request to the daemon. try flareDaemon.requestMinting(topupRequestWei) { } catch Error(string memory message) { revert(message); } catch { revert(ERR_REQUEST_MINT); } } return true; } function switchToFallbackMode() external view override onlyFlareDaemon returns (bool) { // do nothing - there is no fallback mode in Inflation return false; } /** * @notice Implement this function for updating daemonized contracts through AddressUpdater. */ function getContractName() external pure override returns (string memory) { return "Inflation"; } /** * @notice Returns next expected inflation topup time stamp which is also inflation authorization time. * The returned time from this API is actually the time of the block in which the topup is requested. * The Actual topup will take place in the next block. * Expected diff is up to a few seconds (max is less then a minute). */ function getNextExpectedTopupTs () external view returns (uint256 _nextTopupTs) { _nextTopupTs = lastAuthorizationTs.add(AUTHORIZE_TIME_FRAME_SEC); } /** * @notice Implementation of the AddressUpdatable abstract method - updates supply and inflation allocation. * @notice Set a reference to a provider of sharing percentages by inflation receiver. * @dev Assume that sharing percentages sum to 100% if at least one exists, but * if no sharing percentages are defined, then no inflation will be authorized. * @notice Set a reference to a provider of the annual inflation percentage. * @dev Assume that referencing contract has reasonablness limitations on percentages. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { IISupply _supply = IISupply(_getContractAddress(_contractNameHashes, _contractAddresses, "Supply")); emit SupplySet(supply, _supply); supply = _supply; inflationAllocation = IIInflationAllocation( _getContractAddress(_contractNameHashes, _contractAddresses, "InflationAllocation")); emit InflationAllocationSet(inflationAllocation); } function _initNewAnnum(uint256 startTs) internal { supply.updateCirculatingSupply(); uint256 inflatableSupply = supply.getInflatableBalance(); try inflationAllocation.getAnnualPercentageBips() returns(uint256 annualPercentBips) { inflationAnnums.initializeNewAnnum(startTs, inflatableSupply, annualPercentBips); } catch Error(string memory message) { revert(message); } catch { revert(ERR_GET_ANNUAL_PERCENT); } InflationAnnum.InflationAnnumState memory inflationAnnum = inflationAnnums.getCurrentAnnum(); emit NewAnnumInitialized( inflationAnnum.startTimeStamp, inflationAnnum.endTimeStamp, inflatableSupply, inflationAnnum.recognizedInflationWei, inflationAnnum.rewardServices.totalAuthorizedInflationWei, inflationAnnum.rewardServices.totalInflationTopupRequestedWei, inflationAnnum.rewardServices.totalInflationTopupReceivedWei, inflationAnnum.rewardServices.totalInflationTopupWithdrawnWei ); } /** * @notice Compute the expected balance of this contract. * @param _balanceExpectedWei The computed balance expected. */ function getExpectedBalance() private view returns(uint256 _balanceExpectedWei) { return inflationAnnums.totalInflationTopupReceivedWei .sub(inflationAnnums.totalInflationTopupWithdrawnWei) .add(totalSelfDestructReceivedWei); } }
./contracts/addressUpdater/interface/IIAddressUpdatable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIAddressUpdatable { /** * @notice Updates contract addresses - should be called only from AddressUpdater contract * @param _contractNameHashes list of keccak256(abi.encode(...)) contract names * @param _contractAddresses list of contract addresses corresponding to the contract names */ function updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) external; }
./contracts/genesis/implementation/FlareDaemon.sol
// SPDX-License-Identifier: MIT // WARNING, WARNING, WARNING // If you modify this contract, you need to re-install the binary into the validator // genesis file for the chain you wish to run. See ./docs/CompilingContracts.md for more information. // You have been warned. That is all. pragma solidity 0.7.6; pragma abicoder v2; import "../../governance/implementation/GovernedAtGenesis.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../interface/IInflationGenesis.sol"; import "../interface/IFlareDaemonize.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; /** * @title Flare Daemon contract * @notice This contract exists to coordinate regular daemon-like polling of contracts * that are registered to receive said polling. The trigger method is called by the * validator right at the end of block state transition. */ contract FlareDaemon is GovernedAtGenesis, AddressUpdatable { using SafeMath for uint256; using SafePct for uint256; //==================================================================== // Data Structures //==================================================================== struct DaemonizedError { uint192 lastErrorBlock; uint64 numErrors; address fromContract; uint64 errorTypeIndex; string errorMessage; } struct LastErrorData { uint192 totalDaemonizedErrors; uint64 lastErrorTypeIndex; } struct Registration { IFlareDaemonize daemonizedContract; uint256 gasLimit; } string internal constant ERR_ALREADY_SET = "already set"; string internal constant ERR_OUT_OF_BALANCE = "out of balance"; string internal constant ERR_NOT_INFLATION = "not inflation"; string internal constant ERR_TOO_MANY = "too many"; string internal constant ERR_TOO_BIG = "too big"; string internal constant ERR_TOO_OFTEN = "too often"; string internal constant ERR_INFLATION_ZERO = "inflation zero"; string internal constant ERR_BLOCK_NUMBER_SMALL = "block.number small"; string internal constant INDEX_TOO_HIGH = "start index high"; string internal constant UPDATE_GAP_TOO_SHORT = "time gap too short"; string internal constant MAX_MINT_TOO_HIGH = "max mint too high"; string internal constant MAX_MINT_IS_ZERO = "max mint is zero"; string internal constant ERR_DUPLICATE_ADDRESS = "dup address"; string internal constant ERR_ADDRESS_ZERO = "address zero"; string internal constant ERR_OUT_OF_GAS = "out of gas"; string internal constant ERR_INFLATION_MINT_RECEIVE_FAIL = "unknown error. receiveMinting"; uint256 internal constant MAX_DAEMONIZE_CONTRACTS = 10; // Initial max mint request - 60 million native token uint256 internal constant MAX_MINTING_REQUEST_DEFAULT = 60000000 ether; // How often can inflation request minting from the validator - 23 hours constant uint256 internal constant MAX_MINTING_FREQUENCY_SEC = 23 hours; // How often can the maximal mint request amount be updated uint256 internal constant MAX_MINTING_REQUEST_FREQUENCY_SEC = 24 hours; // By how much can the maximum be increased (as a percentage of the previous maximum) uint256 internal constant MAX_MINTING_REQUEST_INCREASE_PERCENT = 110; // upper estimate of gas needed after error occurs in call to daemonizedContract.daemonize() uint256 internal constant MIN_GAS_LEFT_AFTER_DAEMONIZE = 300000; // lower estimate for gas needed for daemonize() call in trigger uint256 internal constant MIN_GAS_FOR_DAEMONIZE_CALL = 5000; IInflationGenesis public inflation; uint256 public systemLastTriggeredAt; uint256 public totalMintingRequestedWei; uint256 public totalMintingReceivedWei; uint256 public totalMintingWithdrawnWei; uint256 public totalSelfDestructReceivedWei; uint256 public maxMintingRequestWei; uint256 public lastMintRequestTs; uint256 public lastUpdateMaxMintRequestTs; LastErrorData public errorData; uint256 public blockHoldoff; uint256 private lastBalance; uint256 private expectedMintRequest; bool private initialized; // track deamonized contracts IFlareDaemonize[] internal daemonizeContracts; mapping (IFlareDaemonize => uint256) internal gasLimits; mapping (IFlareDaemonize => uint256) internal blockHoldoffsRemaining; // track daemonize errors mapping(bytes32 => DaemonizedError) internal daemonizedErrors; bytes32 [] internal daemonizeErrorHashes; event ContractDaemonized(address theContract, uint256 gasConsumed); event ContractDaemonizeErrored(address theContract, uint256 atBlock, string theMessage, uint256 gasConsumed); event ContractHeldOff(address theContract, uint256 blockHoldoffsRemaining); event ContractsSkippedOutOfGas(uint256 numberOfSkippedConstracts); event MintingRequestReceived(uint256 amountWei); event MintingRequestTriggered(uint256 amountWei); event MintingReceived(uint256 amountWei); event MintingWithdrawn(uint256 amountWei); event RegistrationUpdated(IFlareDaemonize theContract, bool add); event SelfDestructReceived(uint256 amountWei); event InflationSet(IInflationGenesis theNewContract, IInflationGenesis theOldContract); /** * @dev As there is not a constructor, this modifier exists to make sure the inflation * contract is set for methods that require it. */ modifier inflationSet { // Don't revert...just report. if (address(inflation) == address(0)) { addDaemonizeError(address(this), ERR_INFLATION_ZERO, 0); } _; } /** * @dev Access control to protect methods to allow only minters to call select methods * (like transferring balance out). */ modifier onlyInflation (address _inflation) { require (address(inflation) == _inflation, ERR_NOT_INFLATION); _; } /** * @dev Access control to protect trigger() method. * Please note that the sender address is the same as deployed FlareDaemon address in this case. */ modifier onlySystemTrigger { require (msg.sender == 0x1000000000000000000000000000000000000002); _; } //==================================================================== // Constructor for pre-compiled code //==================================================================== /** * @dev This constructor should contain no code as this contract is pre-loaded into the genesis block. * The super constructor is called for testing convenience. */ constructor() GovernedAtGenesis(address(0)) AddressUpdatable(address(0)) { /* empty block */ } //==================================================================== // Functions //==================================================================== /** * @notice Register contracts to be polled by the daemon process. * @param _registrations An array of Registration structures of IFlareDaemonize contracts to daemonize * and gas limits for each contract. * @dev A gas limit of zero will set no limit for the contract but the validator has an overall * limit for the trigger() method. * @dev If any registrations already exist, they will be unregistered. * @dev Contracts will be daemonized in the order in which presented via the _registrations array. */ function registerToDaemonize(Registration[] memory _registrations) external onlyGovernance { _registerToDaemonize(_registrations); } /** * @notice Queue up a minting request to send to the validator at next trigger. * @param _amountWei The amount to mint. */ function requestMinting(uint256 _amountWei) external onlyInflation(msg.sender) { require(_amountWei <= maxMintingRequestWei, ERR_TOO_BIG); require(_getNextMintRequestAllowedTs() < block.timestamp, ERR_TOO_OFTEN); if (_amountWei > 0) { lastMintRequestTs = block.timestamp; totalMintingRequestedWei = totalMintingRequestedWei.add(_amountWei); emit MintingRequestReceived(_amountWei); } } /** * @notice Set number of blocks that must elapse before a daemonized contract exceeding gas limit can have * its daemonize() method called again. * @param _blockHoldoff The number of blocks to holdoff. */ function setBlockHoldoff(uint256 _blockHoldoff) external onlyGovernance { blockHoldoff = _blockHoldoff; } /** * @notice Set limit on how much can be minted per request. * @param _maxMintingRequestWei The request maximum in wei. * @notice this number can't be udated too often */ function setMaxMintingRequest(uint256 _maxMintingRequestWei) external onlyGovernance { // make sure increase amount is reasonable require( _maxMintingRequestWei <= (maxMintingRequestWei.mulDiv(MAX_MINTING_REQUEST_INCREASE_PERCENT,100)), MAX_MINT_TOO_HIGH ); require(_maxMintingRequestWei > 0, MAX_MINT_IS_ZERO); // make sure enough time since last update require( block.timestamp > lastUpdateMaxMintRequestTs + MAX_MINTING_REQUEST_FREQUENCY_SEC, UPDATE_GAP_TOO_SHORT ); maxMintingRequestWei = _maxMintingRequestWei; lastUpdateMaxMintRequestTs = block.timestamp; } /** * @notice Sets the address udpater contract. * @param _addressUpdater The address updater contract. */ function setAddressUpdater(address _addressUpdater) external onlyGovernance { require(getAddressUpdater() == address(0), ERR_ALREADY_SET); setAddressUpdaterValue(_addressUpdater); } /** * @notice The meat of this contract. Poll all registered contracts, calling the daemonize() method of each, * in the order in which registered. * @return _toMintWei Return the amount to mint back to the validator. The asked for balance will show * up in the next block (it is actually added right before this block's state transition, * but well after this method call will see it.) * @dev This method watches for balances being added to this contract and handles appropriately - legit * mint requests as made via requestMinting, and also self-destruct sending to this contract, should * it happen for some reason. */ //slither-disable-next-line reentrancy-eth // method protected by reentrancy guard (see comment below) function trigger() external virtual inflationSet onlySystemTrigger returns (uint256 _toMintWei) { return triggerInternal(); } function getDaemonizedContractsData() external view returns( IFlareDaemonize[] memory _daemonizeContracts, uint256[] memory _gasLimits, uint256[] memory _blockHoldoffsRemaining ) { uint256 len = daemonizeContracts.length; _daemonizeContracts = new IFlareDaemonize[](len); _gasLimits = new uint256[](len); _blockHoldoffsRemaining = new uint256[](len); for (uint256 i; i < len; i++) { IFlareDaemonize daemonizeContract = daemonizeContracts[i]; _daemonizeContracts[i] = daemonizeContract; _gasLimits[i] = gasLimits[daemonizeContract]; _blockHoldoffsRemaining[i] = blockHoldoffsRemaining[daemonizeContract]; } } function getNextMintRequestAllowedTs() external view returns(uint256) { return _getNextMintRequestAllowedTs(); } function showLastDaemonizedError () external view returns( uint256[] memory _lastErrorBlock, uint256[] memory _numErrors, string[] memory _errorString, address[] memory _erroringContract, uint256 _totalDaemonizedErrors ) { return showDaemonizedErrors(errorData.lastErrorTypeIndex, 1); } /** * @notice Set the governance address to a hard-coded known address. * @dev This should be done at contract deployment time. * @return The governance address. */ function initialiseFixedAddress() public override returns(address) { if (!initialized) { initialized = true; address governanceAddress = super.initialiseFixedAddress(); return governanceAddress; } else { return governance(); } } function showDaemonizedErrors (uint startIndex, uint numErrorTypesToShow) public view returns( uint256[] memory _lastErrorBlock, uint256[] memory _numErrors, string[] memory _errorString, address[] memory _erroringContract, uint256 _totalDaemonizedErrors ) { require(startIndex < daemonizeErrorHashes.length, INDEX_TOO_HIGH); uint256 numReportElements = daemonizeErrorHashes.length >= startIndex + numErrorTypesToShow ? numErrorTypesToShow : daemonizeErrorHashes.length - startIndex; _lastErrorBlock = new uint256[] (numReportElements); _numErrors = new uint256[] (numReportElements); _errorString = new string[] (numReportElements); _erroringContract = new address[] (numReportElements); // we have error data error type. // error type is hash(error_string, source contract) // per error type we report how many times it happened. // what was last block it happened. // what is the error string. // what is the erroring contract for (uint i = 0; i < numReportElements; i++) { bytes32 hash = daemonizeErrorHashes[startIndex + i]; _lastErrorBlock[i] = daemonizedErrors[hash].lastErrorBlock; _numErrors[i] = daemonizedErrors[hash].numErrors; _errorString[i] = daemonizedErrors[hash].errorMessage; _erroringContract[i] = daemonizedErrors[hash].fromContract; } _totalDaemonizedErrors = errorData.totalDaemonizedErrors; } /** * @notice Implementation of the AddressUpdatable abstract method - updates Inflation and daemonized contracts. * @dev It also sets `maxMintingRequestWei` if it was not set before. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { IInflationGenesis _inflation = IInflationGenesis( _getContractAddress(_contractNameHashes, _contractAddresses, "Inflation")); emit InflationSet(_inflation, inflation); inflation = _inflation; if (maxMintingRequestWei == 0) { maxMintingRequestWei = MAX_MINTING_REQUEST_DEFAULT; } uint256 len = daemonizeContracts.length; if (len == 0) { return; } Registration[] memory registrations = new Registration[](len); for (uint256 i = 0; i < len; i++) { IFlareDaemonize daemonizeContract = daemonizeContracts[i]; registrations[i].daemonizedContract = IFlareDaemonize( _getContractAddress(_contractNameHashes, _contractAddresses, daemonizeContract.getContractName())); registrations[i].gasLimit = gasLimits[daemonizeContract]; } _registerToDaemonize(registrations); } /** * @notice Implementation of the trigger() method. The external wrapper has extra guard for msg.sender. */ //slither-disable-next-line reentrancy-eth // method protected by reentrancy guard (see comment below) function triggerInternal() internal returns (uint256 _toMintWei) { // only one trigger() call per block allowed // this also serves as reentrancy guard, since any re-entry will happen in the same block if(block.number == systemLastTriggeredAt) return 0; systemLastTriggeredAt = block.number; uint256 currentBalance = address(this).balance; // Did the validator or a self-destructor conjure some native token? if (currentBalance > lastBalance) { uint256 balanceExpected = lastBalance.add(expectedMintRequest); // Did we get what was last asked for? if (currentBalance == balanceExpected) { // Yes, so assume it all came from the validator. uint256 minted = expectedMintRequest; totalMintingReceivedWei = totalMintingReceivedWei.add(minted); emit MintingReceived(minted); //slither-disable-next-line arbitrary-send // only sent to inflation, set by governance try inflation.receiveMinting{ value: minted }() { totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(minted); emit MintingWithdrawn(minted); } catch Error(string memory message) { addDaemonizeError(address(this), message, 0); } catch { addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0); } } else if (currentBalance < balanceExpected) { // No, and if less, there are two possibilities: 1) the validator did not // send us what we asked (not possible unless a bug), or 2) an attacker // sent us something in between a request and a mint. Assume 2. uint256 selfDestructReceived = currentBalance.sub(lastBalance); totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived); emit SelfDestructReceived(selfDestructReceived); } else { // No, so assume we got a minting request (perhaps zero...does not matter) // and some self-destruct proceeds (unlikely but can happen). totalMintingReceivedWei = totalMintingReceivedWei.add(expectedMintRequest); uint256 selfDestructReceived = currentBalance.sub(lastBalance).sub(expectedMintRequest); totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived); emit MintingReceived(expectedMintRequest); emit SelfDestructReceived(selfDestructReceived); //slither-disable-next-line arbitrary-send // only sent to inflation, set by governance try inflation.receiveMinting{ value: expectedMintRequest }() { totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(expectedMintRequest); emit MintingWithdrawn(expectedMintRequest); } catch Error(string memory message) { addDaemonizeError(address(this), message, 0); } catch { addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0); } } } uint256 len = daemonizeContracts.length; // Perform trigger operations here for (uint256 i = 0; i < len; i++) { IFlareDaemonize daemonizedContract = daemonizeContracts[i]; uint256 blockHoldoffRemainingForContract = blockHoldoffsRemaining[daemonizedContract]; if (blockHoldoffRemainingForContract > 0) { blockHoldoffsRemaining[daemonizedContract] = blockHoldoffRemainingForContract - 1; emit ContractHeldOff(address(daemonizedContract), blockHoldoffRemainingForContract); } else { // Figure out what gas to limit call by uint256 gasLimit = gasLimits[daemonizedContract]; uint256 startGas = gasleft(); // End loop if there isn't enough gas left for any daemonize call if (startGas < MIN_GAS_LEFT_AFTER_DAEMONIZE + MIN_GAS_FOR_DAEMONIZE_CALL) { emit ContractsSkippedOutOfGas(len - i); break; } // Calculate the gas limit for the next call uint256 useGas = startGas - MIN_GAS_LEFT_AFTER_DAEMONIZE; if (gasLimit > 0 && gasLimit < useGas) { useGas = gasLimit; } // Run daemonize for the contract, consume errors, and record try daemonizedContract.daemonize{gas: useGas}() { emit ContractDaemonized(address(daemonizedContract), (startGas - gasleft())); // Catch all requires with messages } catch Error(string memory message) { addDaemonizeError(address(daemonizedContract), message, (startGas - gasleft())); daemonizedContract.switchToFallbackMode(); // Catch everything else...out of gas, div by zero, asserts, etc. } catch { uint256 endGas = gasleft(); // Interpret out of gas errors if (gasLimit > 0 && startGas.sub(endGas) >= gasLimit) { addDaemonizeError(address(daemonizedContract), ERR_OUT_OF_GAS, (startGas - endGas)); // When daemonize() fails with out-of-gas, try to fix it in two steps: // 1) try to switch contract to fallback mode // (to allow the contract's daemonize() to recover in fallback mode in next block) // 2) if constract is already in fallback mode or fallback mode is not supported // (switchToFallbackMode() returns false), start the holdoff for this contract bool switchedToFallback = daemonizedContract.switchToFallbackMode(); if (!switchedToFallback) { blockHoldoffsRemaining[daemonizedContract] = blockHoldoff; } } else { // Don't know error cause...just log it as unknown addDaemonizeError(address(daemonizedContract), "unknown", (startGas - endGas)); daemonizedContract.switchToFallbackMode(); } } } } // Get any requested minting and return to validator _toMintWei = getPendingMintRequest(); if (_toMintWei > 0) { expectedMintRequest = _toMintWei; emit MintingRequestTriggered(_toMintWei); } else { expectedMintRequest = 0; } // Update balance lastBalance = address(this).balance; // We should be in balance - don't revert, just report... uint256 contractBalanceExpected = getExpectedBalance(); if (contractBalanceExpected != address(this).balance) { addDaemonizeError(address(this), ERR_OUT_OF_BALANCE, 0); } } function addDaemonizeError(address daemonizedContract, string memory message, uint256 gasConsumed) internal { bytes32 errorStringHash = keccak256(abi.encode(daemonizedContract, message)); DaemonizedError storage daemonizedError = daemonizedErrors[errorStringHash]; if (daemonizedError.numErrors == 0) { // first time we recieve this error string. daemonizeErrorHashes.push(errorStringHash); daemonizedError.fromContract = daemonizedContract; // limit message length to fit in fixed number of storage words (to make gas usage predictable) daemonizedError.errorMessage = truncateString(message, 64); daemonizedError.errorTypeIndex = uint64(daemonizeErrorHashes.length - 1); } daemonizedError.numErrors += 1; daemonizedError.lastErrorBlock = uint192(block.number); emit ContractDaemonizeErrored(daemonizedContract, block.number, message, gasConsumed); errorData.totalDaemonizedErrors += 1; errorData.lastErrorTypeIndex = daemonizedError.errorTypeIndex; } /** * @notice Register contracts to be polled by the daemon process. * @param _registrations An array of Registration structures of IFlareDaemonize contracts to daemonize * and gas limits for each contract. * @dev A gas limit of zero will set no limit for the contract but the validator has an overall * limit for the trigger() method. * @dev If any registrations already exist, they will be unregistered. * @dev Contracts will be daemonized in the order in which presented via the _registrations array. */ function _registerToDaemonize(Registration[] memory _registrations) internal { // Make sure there are not too many contracts to register. uint256 registrationsLength = _registrations.length; require(registrationsLength <= MAX_DAEMONIZE_CONTRACTS, ERR_TOO_MANY); // Unregister everything first _unregisterAll(); // Loop over all contracts to register for (uint256 registrationIndex = 0; registrationIndex < registrationsLength; registrationIndex++) { // Address cannot be zero require(address(_registrations[registrationIndex].daemonizedContract) != address(0), ERR_ADDRESS_ZERO); uint256 daemonizeContractsLength = daemonizeContracts.length; // Make sure no dups...yes, inefficient. Registration should not be done often. for (uint256 i = 0; i < daemonizeContractsLength; i++) { require(_registrations[registrationIndex].daemonizedContract != daemonizeContracts[i], ERR_DUPLICATE_ADDRESS); // already registered } // Store off the registered contract to daemonize, in the order presented. daemonizeContracts.push(_registrations[registrationIndex].daemonizedContract); // Record the gas limit for the contract. gasLimits[_registrations[registrationIndex].daemonizedContract] = _registrations[registrationIndex].gasLimit; // Clear any blocks being held off for the given contract, if any. Contracts may be re-presented // if only order is being modified, for example. blockHoldoffsRemaining[_registrations[registrationIndex].daemonizedContract] = 0; emit RegistrationUpdated (_registrations[registrationIndex].daemonizedContract, true); } } /** * @notice Unregister all contracts from being polled by the daemon process. */ function _unregisterAll() private { uint256 len = daemonizeContracts.length; for (uint256 i = 0; i < len; i++) { IFlareDaemonize daemonizedContract = daemonizeContracts[daemonizeContracts.length - 1]; daemonizeContracts.pop(); emit RegistrationUpdated (daemonizedContract, false); } } /** * @notice Net totals to obtain the expected balance of the contract. */ function getExpectedBalance() private view returns(uint256 _balanceExpectedWei) { _balanceExpectedWei = totalMintingReceivedWei. sub(totalMintingWithdrawnWei). add(totalSelfDestructReceivedWei); } /** * @notice Net total received from total requested. */ function getPendingMintRequest() private view returns(uint256 _mintRequestPendingWei) { _mintRequestPendingWei = totalMintingRequestedWei.sub(totalMintingReceivedWei); } function _getNextMintRequestAllowedTs() internal view returns (uint256) { return (lastMintRequestTs + MAX_MINTING_FREQUENCY_SEC); } function truncateString(string memory _str, uint256 _maxlength) private pure returns (string memory) { bytes memory strbytes = bytes(_str); if (strbytes.length <= _maxlength) { return _str; } bytes memory result = new bytes(_maxlength); for (uint256 i = 0; i < _maxlength; i++) { result[i] = strbytes[i]; } return string(result); } }
./contracts/addressUpdater/implementation/AddressUpdatable.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../interface/IIAddressUpdatable.sol"; abstract contract AddressUpdatable is IIAddressUpdatable { // https://docs.soliditylang.org/en/v0.8.7/contracts.html#constant-and-immutable-state-variables // No storage slot is allocated bytes32 internal constant ADDRESS_STORAGE_POSITION = keccak256("flare.diamond.AddressUpdatable.ADDRESS_STORAGE_POSITION"); modifier onlyAddressUpdater() { require (msg.sender == getAddressUpdater(), "only address updater"); _; } constructor(address _addressUpdater) { setAddressUpdaterValue(_addressUpdater); } function getAddressUpdater() public view returns (address _addressUpdater) { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { _addressUpdater := sload(position) } } /** * @notice external method called from AddressUpdater only */ function updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) external override onlyAddressUpdater { // update addressUpdater address setAddressUpdaterValue(_getContractAddress(_contractNameHashes, _contractAddresses, "AddressUpdater")); // update all other addresses _updateContractAddresses(_contractNameHashes, _contractAddresses); } /** * @notice virtual method that a contract extending AddressUpdatable must implement */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal virtual; /** * @notice helper method to get contract address * @dev it reverts if contract name does not exist */ function _getContractAddress( bytes32[] memory _nameHashes, address[] memory _addresses, string memory _nameToFind ) internal pure returns(address) { bytes32 nameHash = keccak256(abi.encode(_nameToFind)); address a = address(0); for (uint256 i = 0; i < _nameHashes.length; i++) { if (nameHash == _nameHashes[i]) { a = _addresses[i]; break; } } require(a != address(0), "address zero"); return a; } function setAddressUpdaterValue(address _addressUpdater) internal { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { sstore(position, _addressUpdater) } } }
./contracts/genesis/interface/IFlareDaemonize.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; /// Any contracts that want to recieve a trigger from Flare daemon should /// implement IFlareDaemonize interface IFlareDaemonize { /// Implement this function for recieving a trigger from FlareDaemon. function daemonize() external returns (bool); /// This function will be called after an error is caught in daemonize(). /// It will switch the contract to a simpler fallback mode, which hopefully works when full mode doesn't. /// Not every contract needs to support fallback mode (FtsoManager does), so this method may be empty. /// Switching back to normal mode is left to the contract (typically a governed method call). /// This function may be called due to low-gas error, so it shouldn't use more than ~30.000 gas. /// @return true if switched to fallback mode, false if already in fallback mode or if falback not supported function switchToFallbackMode() external returns (bool); /// Implement this function for updating daemonized contracts through AddressUpdater. function getContractName() external view returns (string memory); }
./contracts/genesis/interface/IInflationGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IInflationGenesis { /** * @notice Receive newly minted native tokens from the FlareDaemon. * @dev Assume that the amount received will be >= last topup requested across all services. * If there is not enough balance sent to cover the topup request, expect library method will revert. * Also assume that any balance received greater than the topup request calculated * came from self-destructor sending a balance to this contract. */ function receiveMinting() external payable; }
./contracts/governance/implementation/Governed.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import { GovernedBase } from "./GovernedBase.sol"; /** * @title Governed * @dev For deployed, governed contracts, enforce a non-zero address at create time. **/ contract Governed is GovernedBase { constructor(address _governance) GovernedBase(_governance) { require(_governance != address(0), "_governance zero"); } }
./contracts/governance/implementation/GovernedAtGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./GovernedBase.sol"; /** * @title Governed At Genesis * @dev This contract enforces a fixed governance address when the constructor * is not executed on a contract (for instance when directly loaded to the genesis block). * This is required to fix governance on a contract when the network starts, at such point * where theoretically no accounts yet exist, and leaving it ungoverned could result in a race * to claim governance by an unauthorized address. **/ contract GovernedAtGenesis is GovernedBase { constructor(address _governance) GovernedBase(_governance) { } /** * @notice Set governance to a fixed address when constructor is not called. **/ function initialiseFixedAddress() public virtual returns (address) { address governanceAddress = address(0xfffEc6C83c8BF5c3F4AE0cCF8c45CE20E4560BD7); super.initialise(governanceAddress); return governanceAddress; } /** * @notice Disallow initialise to be called * @param _governance The governance address for initial claiming **/ // solhint-disable-next-line no-unused-vars function initialise(address _governance) public override pure { assert(false); } }
./contracts/governance/implementation/GovernedBase.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../../userInterfaces/IGovernanceSettings.sol"; /** * @title Governed Base * @notice This abstract base class defines behaviors for a governed contract. * @dev This class is abstract so that specific behaviors can be defined for the constructor. * Contracts should not be left ungoverned, but not all contract will have a constructor * (for example those pre-defined in genesis). **/ abstract contract GovernedBase { struct TimelockedCall { uint256 allowedAfterTimestamp; bytes encodedCall; } // solhint-disable-next-line const-name-snakecase IGovernanceSettings public constant governanceSettings = IGovernanceSettings(0x1000000000000000000000000000000000000007); address private initialGovernance; bool private initialised; bool public productionMode; bool private executing; mapping(bytes4 => TimelockedCall) public timelockedCalls; event GovernanceCallTimelocked(bytes4 selector, uint256 allowedAfterTimestamp, bytes encodedCall); event TimelockedGovernanceCallExecuted(bytes4 selector, uint256 timestamp); event TimelockedGovernanceCallCanceled(bytes4 selector, uint256 timestamp); event GovernanceInitialised(address initialGovernance); event GovernedProductionModeEntered(address governanceSettings); modifier onlyGovernance { if (executing || !productionMode) { _beforeExecute(); _; } else { _recordTimelockedCall(msg.data); } } modifier onlyImmediateGovernance () { _checkOnlyGovernance(); _; } constructor(address _initialGovernance) { if (_initialGovernance != address(0)) { initialise(_initialGovernance); } } /** * @notice Execute the timelocked governance calls once the timelock period expires. * @dev Only executor can call this method. * @param _selector The method selector (only one timelocked call per method is stored). */ function executeGovernanceCall(bytes4 _selector) external { require(governanceSettings.isExecutor(msg.sender), "only executor"); TimelockedCall storage call = timelockedCalls[_selector]; require(call.allowedAfterTimestamp != 0, "timelock: invalid selector"); require(block.timestamp >= call.allowedAfterTimestamp, "timelock: not allowed yet"); bytes memory encodedCall = call.encodedCall; delete timelockedCalls[_selector]; executing = true; //solhint-disable-next-line avoid-low-level-calls (bool success,) = address(this).call(encodedCall); executing = false; emit TimelockedGovernanceCallExecuted(_selector, block.timestamp); _passReturnOrRevert(success); } /** * Cancel a timelocked governance call before it has been executed. * @dev Only governance can call this method. * @param _selector The method selector. */ function cancelGovernanceCall(bytes4 _selector) external onlyImmediateGovernance { require(timelockedCalls[_selector].allowedAfterTimestamp != 0, "timelock: invalid selector"); emit TimelockedGovernanceCallCanceled(_selector, block.timestamp); delete timelockedCalls[_selector]; } /** * Enter the production mode after all the initial governance settings have been set. * This enables timelocks and the governance is afterwards obtained by calling * governanceSettings.getGovernanceAddress(). */ function switchToProductionMode() external { _checkOnlyGovernance(); require(!productionMode, "already in production mode"); initialGovernance = address(0); productionMode = true; emit GovernedProductionModeEntered(address(governanceSettings)); } /** * @notice Initialize the governance address if not first initialized. */ function initialise(address _initialGovernance) public virtual { require(initialised == false, "initialised != false"); initialised = true; initialGovernance = _initialGovernance; emit GovernanceInitialised(_initialGovernance); } /** * Returns the current effective governance address. */ function governance() public view returns (address) { return productionMode ? governanceSettings.getGovernanceAddress() : initialGovernance; } function _beforeExecute() private { if (executing) { // can only be run from executeGovernanceCall(), where we check that only executor can call // make sure nothing else gets executed, even in case of reentrancy assert(msg.sender == address(this)); executing = false; } else { // must be called with: productionMode=false // must check governance in this case _checkOnlyGovernance(); } } function _recordTimelockedCall(bytes calldata _data) private { _checkOnlyGovernance(); bytes4 selector; //solhint-disable-next-line no-inline-assembly assembly { selector := calldataload(_data.offset) } uint256 timelock = governanceSettings.getTimelock(); uint256 allowedAt = block.timestamp + timelock; timelockedCalls[selector] = TimelockedCall({ allowedAfterTimestamp: allowedAt, encodedCall: _data }); emit GovernanceCallTimelocked(selector, allowedAt, _data); } function _checkOnlyGovernance() private view { require(msg.sender == governance(), "only governance"); } function _passReturnOrRevert(bool _success) private pure { // pass exact return or revert data - needs to be done in assembly //solhint-disable-next-line no-inline-assembly assembly { let size := returndatasize() let ptr := mload(0x40) mstore(0x40, add(ptr, size)) returndatacopy(ptr, 0, size) if _success { return(ptr, size) } revert(ptr, size) } } }
./contracts/inflation/interface/IIInflationAllocation.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; import "./IIInflationPercentageProvider.sol"; import "./IIInflationSharingPercentageProvider.sol"; interface IIInflationAllocation is IIInflationPercentageProvider, IIInflationSharingPercentageProvider { }
./contracts/inflation/interface/IIInflationPercentageProvider.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIInflationPercentageProvider { /** * Return the annual inflation rate in bips. */ function getAnnualPercentageBips() external returns(uint256); }
./contracts/inflation/interface/IIInflationReceiver.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIInflationReceiver { /** * Notify the receiver that it is entitled to receive `_toAuthorizeWei` inflation amount. * @param _toAuthorizeWei the amount of inflation that can be awarded in the coming day */ function setDailyAuthorizedInflation(uint256 _toAuthorizeWei) external; /** * Receive native tokens from inflation. */ function receiveInflation() external payable; /** * Inflation receivers have a reference to the Inflation contract. */ function getInflationAddress() external returns(address); /** * Implement this function for updating inflation receiver contracts through AddressUpdater. */ function getContractName() external view returns (string memory); }
./contracts/inflation/interface/IIInflationSharingPercentageProvider.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; import "./IIInflationReceiver.sol"; struct SharingPercentage { IIInflationReceiver inflationReceiver; uint256 percentBips; } interface IIInflationSharingPercentageProvider { /** * Return the shared percentage per inflation receiver. * @dev Assumption is that implementer edited that percents sum to 100 pct and * that receiver addresses are valid. */ function getSharingPercentages() external returns(SharingPercentage[] memory); }
@openzeppelin/contracts/math/Math.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
./contracts/inflation/interface/IISupply.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IISupply { /** * @notice Updates circulating supply * @dev Also updates the burn address amount */ function updateCirculatingSupply() external; /** * @notice Updates authorized inflation and circulating supply - emits event if error * @param _inflationAuthorizedWei Authorized inflation * @dev Also updates the burn address amount */ function updateAuthorizedInflationAndCirculatingSupply(uint256 _inflationAuthorizedWei) external; /** * @notice Get approximate circulating supply for given block number from cache - only past block * @param _blockNumber Block number * @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber */ function getCirculatingSupplyAtCached(uint256 _blockNumber) external returns(uint256 _circulatingSupplyWei); /** * @notice Get approximate circulating supply for given block number * @param _blockNumber Block number * @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber */ function getCirculatingSupplyAt(uint256 _blockNumber) external view returns(uint256 _circulatingSupplyWei); /** * @notice Get total inflatable balance (initial genesis amount + total authorized inflation) * @return _inflatableBalanceWei Return inflatable balance */ function getInflatableBalance() external view returns(uint256 _inflatableBalanceWei); }
./contracts/inflation/lib/InflationAnnum.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../../utils/implementation/DateTimeLibrary.sol"; import "./RewardServices.sol"; import "@openzeppelin/contracts/math/Math.sol"; import "@openzeppelin/contracts/utils/SafeCast.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; /** * @title Inflation Annum library * @notice A library to manage an inflation annum. **/ library InflationAnnum { using BokkyPooBahsDateTimeLibrary for uint256; using InflationAnnum for InflationAnnum.InflationAnnumState; using SafeCast for uint256; using SafeMath for uint256; using SafePct for uint256; /** * @dev `InflationAnnumState` is state structure used by this library to manage * an inflation annum. */ struct InflationAnnumState { uint256 recognizedInflationWei; uint256 startTimeStamp; uint256 endTimeStamp; RewardServices.RewardServicesState rewardServices; } uint256 internal constant BIPS100 = 1e4; // 100% in basis points uint256 internal constant MAX_ANNUAL_INFLATION = 5000000000 ether; /** * @notice Helper function to compute recognized inflation. * @param _inflatableBalance The balance used to recognize inflation. * @param _annualInflationPercentageBips The annual percentage used to recognize inflation. * @return The computed recognized inflation. */ function _computeRecognizedInflationWei( uint256 _inflatableBalance, uint256 _annualInflationPercentageBips ) internal pure returns(uint256) { return Math.min( _inflatableBalance.mulDiv(_annualInflationPercentageBips, 12 * BIPS100), MAX_ANNUAL_INFLATION.div(12) ); // monthly inflation } /** * @notice Helper function to compute the number of days remaining in an annum. * @param _atTimeStamp Compute the number of days for the annum at this time stamp. * @return The number of days computed. * @dev If _atTimeStamp is after the end of the annum, 0 days will be returned. */ function _computeDaysRemainingInAnnum( InflationAnnumState storage _self, uint256 _atTimeStamp ) internal view returns(uint256) { uint256 endTimeStamp = _self.endTimeStamp; if (_atTimeStamp > endTimeStamp) { return 0; } else { return _atTimeStamp.diffDays(endTimeStamp); } } /** * @notice Given a start time stamp, compute the end time stamp for an annum. * @param _startTimeStamp The start time stamp for an annum. * @return The end time stamp for the annum. */ function _getAnnumEndsTs(uint256 _startTimeStamp) internal pure returns (uint256) { // This should cover passing through Feb 29 return _startTimeStamp.addDays(30).subSeconds(1); } /** * @notice Compute the number of periods remaining within an annum. * @param _atTimeStamp Compute periods remaining at this time stamp. * @return The number of periods remaining. * @dev The number of periods must include the current day. */ function getPeriodsRemaining( InflationAnnumState storage _self, uint256 _atTimeStamp ) internal view returns(uint256) { assert(_atTimeStamp <= _self.endTimeStamp); // Add 1 to the periods remaining because the difference between days does not count the current day. return _computeDaysRemainingInAnnum(_self, _atTimeStamp).add(1); } /** * @notice Initialize a new annum data structure. * @param _startTimeStamp The start time stamp of the new annum. * @param _inflatableBalanceWei The inflatable balance used to calculate recognized inflation for the new annum. * @param _annualInflationPercentageBips The annual inflation percentage in bips to calc recognized inflation. * @dev A newly created InflationAnnumState is expected to exist. */ function initialize( InflationAnnumState storage _self, uint256 _startTimeStamp, uint256 _inflatableBalanceWei, uint256 _annualInflationPercentageBips ) internal { _self.startTimeStamp = _startTimeStamp; _self.recognizedInflationWei = _computeRecognizedInflationWei( _inflatableBalanceWei, _annualInflationPercentageBips); _self.endTimeStamp = _getAnnumEndsTs(_startTimeStamp); } }
./contracts/inflation/lib/InflationAnnums.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../implementation/Inflation.sol"; import "./InflationAnnum.sol"; import "./RewardServices.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; import "../interface/IIInflationSharingPercentageProvider.sol"; /** * @title Inflation Annums library * @notice A library to manage a collection of inflation annum and associated totals. * @dev Operations such as authorizing daily inflation are dispatched from this collection * library because the result of the authorization is added to the total authorized across * all annums, which is a concern of this library and not the concern of a given annum, nor the caller. **/ library InflationAnnums { using InflationAnnum for InflationAnnum.InflationAnnumState; using RewardServices for RewardServices.RewardServicesState; using SafeMath for uint256; using SafePct for uint256; /** * @dev `InflationAnnumsState` is state structure used by this library to manage * a collection of inflation annums and associated totals. */ struct InflationAnnumsState { // Collection of annums InflationAnnum.InflationAnnumState[] inflationAnnums; uint256 currentAnnum; // Balances uint256 totalRecognizedInflationWei; uint256 totalAuthorizedInflationWei; uint256 totalInflationTopupRequestedWei; uint256 totalInflationTopupReceivedWei; uint256 totalInflationTopupWithdrawnWei; } string internal constant ERR_NO_ANNUM = "no annum"; string internal constant ERR_TOO_EARLY = "too early"; /** * @notice Dispatch inflation authorization to be performed across all reward services according to their * sharing percentage for the current annum, and then maintain sum total of inflation * authorized across all annums. * @param _atTimeStamp The timestamp at which the number of daily periods remaining in the current * annum will be calculated. * @param _sharingPercentages An array of the sharing percentages by inflation receiver used to * allocate authorized inflation. * @return _amountAuthorizedWei The amount of inflation authorized for this authorization cycle. * @dev Invariant: total inflation authorized cannot be greater than total inflation recognized. */ function authorizeDailyInflation( InflationAnnumsState storage _self, uint256 _atTimeStamp, SharingPercentage[] memory _sharingPercentages ) internal returns(uint256 _amountAuthorizedWei) { // Get the current annum InflationAnnum.InflationAnnumState storage currentAnnum = getCurrentAnnum(_self); // Authorize daily inflation for the current annum, across reward services, given // sharing percentages. _amountAuthorizedWei = currentAnnum.rewardServices.authorizeDailyInflation( _self.totalRecognizedInflationWei, _self.totalAuthorizedInflationWei, currentAnnum.getPeriodsRemaining(_atTimeStamp), _sharingPercentages); // Accumulate total authorized inflation across all annums _self.totalAuthorizedInflationWei = _self.totalAuthorizedInflationWei.add(_amountAuthorizedWei); // Make sure that total authorized never exceeds total recognized assert(_self.totalAuthorizedInflationWei <= _self.totalRecognizedInflationWei); } /** * @notice Dispatch topup request calculations across reward services and sum up total mint request made * to fund topup of reward services. * @param _inflation The Inflation contract containing the topup confguration of each reward service. * @return _topupRequestWei The amount of native token requested to be minted across reward services for * this cycle. * @dev Invariant: total inflation topup requested cannot exceed total inflation authorized */ function computeTopupRequest( InflationAnnumsState storage _self, Inflation _inflation ) internal returns(uint256 _topupRequestWei) { // Get the current annum InflationAnnum.InflationAnnumState storage currentAnnum = getCurrentAnnum(_self); // Compute the topup _topupRequestWei = currentAnnum.rewardServices.computeTopupRequest(_inflation); // Sum the topup request total across annums _self.totalInflationTopupRequestedWei = _self.totalInflationTopupRequestedWei.add(_topupRequestWei); // Make sure that total topup requested can never exceed inflation authorized assert(_self.totalInflationTopupRequestedWei <= _self.totalAuthorizedInflationWei); } /** * @notice Receive minted native tokens (and fund) to satisfy reward services topup requests. * @return _amountPostedWei The native tokens posted (funded) to reward service contracts. * @dev Invariants: * 1) Native tokens topup received cannot exceed native tokens topup requested * 2) Native tokens topup withdrawn for funding cannot exceed native tokens topup received */ function receiveTopupRequest( InflationAnnumsState storage _self ) internal returns(uint256 _amountPostedWei) { // Get the current annum InflationAnnum.InflationAnnumState storage currentAnnum = getCurrentAnnum(_self); // Receive minting of topup request. Post to received and withdrawn buckets for each reward service. _amountPostedWei = currentAnnum.rewardServices.receiveTopupRequest(); // Post the amount of native tokens received into the Inflation contract _self.totalInflationTopupReceivedWei = _self.totalInflationTopupReceivedWei.add(_amountPostedWei); // Received should never be more than requested assert(_self.totalInflationTopupReceivedWei <= _self.totalInflationTopupRequestedWei); // Post amount withdrawn and transferred to reward service contracts _self.totalInflationTopupWithdrawnWei = _self.totalInflationTopupWithdrawnWei.add(_amountPostedWei); // Withdrawn should never be more than received assert(_self.totalInflationTopupWithdrawnWei <= _self.totalInflationTopupReceivedWei); } /** * @notice Get the number of inflation annums. * @return The count. */ function getCount(InflationAnnumsState storage _self) internal view returns(uint256) { return _self.inflationAnnums.length; } /** * @notice Given an index, return a given inflation annum data. * @param _index The index of the annum to fetch. * @return _inflationAnnum Returns InflationAnnum.InflationAnnumState found at _index. * @dev Will revert if index not found. */ function getAnnum( InflationAnnumsState storage _self, uint256 _index ) internal view returns (InflationAnnum.InflationAnnumState storage _inflationAnnum) { require(_index < getCount(_self), ERR_NO_ANNUM); _inflationAnnum = _self.inflationAnnums[_index]; } /** * @notice Return inflation annum data for the current annum. * @return _inflationAnnum Returns InflationAnnum.InflationAnnumState for the current annum. * @dev Will revert if no current annum. */ function getCurrentAnnum( InflationAnnumsState storage _self ) internal view returns (InflationAnnum.InflationAnnumState storage _inflationAnnum) { require(getCount(_self) > 0, ERR_NO_ANNUM); _inflationAnnum = _self.inflationAnnums[_self.currentAnnum]; } /** * @notice Initialize a new annum, add it to the annum collection, maintian running total * of recognized inflation resulting from new annum, and set current annum pointer. * @param _startTimeStamp The timestamp to start the annum. * @param _inflatableBalance The balance to use when recognizing inflation for the annum. * @param _annualInflationPercentageBips The inflation percentage in bips to use when recognizing inflation. */ function initializeNewAnnum( InflationAnnumsState storage _self, uint256 _startTimeStamp, uint256 _inflatableBalance, uint256 _annualInflationPercentageBips ) internal { // Start time cannot be before last annum ends if (getCount(_self) > 0) { require(_startTimeStamp > getCurrentAnnum(_self).endTimeStamp, ERR_TOO_EARLY); } // Create an empty annum InflationAnnum.InflationAnnumState storage inflationAnnum = _self.inflationAnnums.push(); // Initialize it with newly passed in annum info inflationAnnum.initialize(_startTimeStamp, _inflatableBalance, _annualInflationPercentageBips); // Accumulate total recognized inflation across annums _self.totalRecognizedInflationWei = _self.totalRecognizedInflationWei.add(inflationAnnum.recognizedInflationWei); // Reposition index pointing to current annum if (_self.inflationAnnums.length > 1) { _self.currentAnnum = _self.currentAnnum.add(1); } } }
./contracts/inflation/lib/RewardService.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../interface/IIInflationReceiver.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; enum TopupType{ FACTOROFDAILYAUTHORIZED, ALLAUTHORIZED } /** * @notice A struct that defines how mint request topups will be computed for a reward service. * @param topupType The type to signal how the topup amounts are to be calculated. * FACTOROFDAILYAUTHORIZED = Use a factor of last daily authorized to set a * target balance for a reward service to maintain as a reserve for claiming. * ALLAUTHORIZED = Mint enough native tokens to topup reward service contract to hold * all authorized but unrequested rewards. * @param topupFactorX100 If _topupType == FACTOROFDAILYAUTHORIZED, then this factor (times 100) * is multipled by last daily authorized inflation to obtain the * maximum balance that a reward service can hold at any given time. If it holds less, * then this max amount is used to compute the mint request topup required to * bring the reward service contract native token balance up to that amount. */ struct TopupConfiguration { TopupType topupType; // Topup algo type uint256 topupFactorX100; // Topup factor, times 100, if applicable for type bool configured; // Flag to indicate whether initially configured } /** * @title Reward Service library * @notice A library representing a reward service. A reward service consists of a reward contract and * associated inflation-related totals. When a topup configuration is applied, a reward service can * also make minting requests to topup native tokens within a reward contract. * @dev A reward service exists within the context of a given inflation annum. **/ library RewardService { using SafeMath for uint256; using SafePct for uint256; /** * @dev `RewardServiceState` is state structure used by this library to manage * an a reward service tracking authorize inflation. */ struct RewardServiceState { IIInflationReceiver inflationReceiver; // The target rewarding contract uint256 authorizedInflationWei; // Total authorized inflation for this reward service uint256 lastDailyAuthorizedInflationWei; // Last daily authorized inflation amount uint256 inflationTopupRequestedWei; // Total inflation topup requested to be minted uint256 inflationTopupReceivedWei; // Total inflation minting received uint256 inflationTopupWithdrawnWei; // Total inflation minting sent to rewarding service contract } event RewardServiceTopupComputed(IIInflationReceiver inflationReceiver, uint256 amountWei); /** * @notice Maintain authorized inflation total for service. * @param _amountWei Amount to add. */ function addAuthorizedInflation(RewardServiceState storage _self, uint256 _amountWei) internal { _self.authorizedInflationWei = _self.authorizedInflationWei.add(_amountWei); _self.lastDailyAuthorizedInflationWei = _amountWei; } /** * @notice Maintain topup native tokens received total for service. * @param _amountWei Amount to add. */ function addTopupReceived(RewardServiceState storage _self, uint256 _amountWei) internal { _self.inflationTopupReceivedWei = _self.inflationTopupReceivedWei.add(_amountWei); } /** * @notice Maintain topup native tokens withdrawn (funded) total for service. * @param _amountWei Amount to add. */ function addTopupWithdrawn(RewardServiceState storage _self, uint256 _amountWei) internal { _self.inflationTopupWithdrawnWei = _self.inflationTopupWithdrawnWei.add(_amountWei); } /** * @notice Given a topup configuration, compute the topup request for the reward contract associated * to the service. * @param _topupConfiguration The topup configuration defining the algo used to compute the topup amount. * @return _topupRequestWei The topup request amount computed. */ function computeTopupRequest( RewardServiceState storage _self, TopupConfiguration memory _topupConfiguration ) internal returns (uint256 _topupRequestWei) { // Get the balance of the inflation receiver uint256 inflationReceiverBalanceWei = address(_self.inflationReceiver).balance; if (_topupConfiguration.topupType == TopupType.FACTOROFDAILYAUTHORIZED) { // Compute a topup request based purely on the given factor, the last daily authorization, and // the balance that is sitting in the reward service contract. uint256 requestedBalanceWei = _self.lastDailyAuthorizedInflationWei .mulDiv(_topupConfiguration.topupFactorX100, 100); uint256 rawTopupRequestWei = 0; // If current balance is less then requested, request some more. if (requestedBalanceWei > inflationReceiverBalanceWei) { rawTopupRequestWei = requestedBalanceWei.sub(inflationReceiverBalanceWei); } // Compute what is already pending to be topped up uint256 topupPendingWei = getPendingTopup(_self); // If what is pending to topup is greater than the raw request, request no more. if (topupPendingWei > rawTopupRequestWei) { _topupRequestWei = 0; } else { // Back out any request that is already pending _topupRequestWei = rawTopupRequestWei.sub(topupPendingWei); } // And finally, in any case, topup requested cannot be more than the net of // authorized, pending, and received uint256 maxTopupRequestWei = _self.authorizedInflationWei .sub(topupPendingWei) .sub(_self.inflationTopupReceivedWei); if (_topupRequestWei > maxTopupRequestWei) { _topupRequestWei = maxTopupRequestWei; } } else if (_topupConfiguration.topupType == TopupType.ALLAUTHORIZED) { _topupRequestWei = _self.authorizedInflationWei .sub(_self.inflationTopupRequestedWei); } else { // This code is unreachable since TopupType currently has only 2 constructors _topupRequestWei = 0; assert(false); } _self.inflationTopupRequestedWei = _self.inflationTopupRequestedWei.add(_topupRequestWei); emit RewardServiceTopupComputed(_self.inflationReceiver, _topupRequestWei); } /** * @notice Compute a pending topup request. * @return _pendingTopupWei The amount pending to be minted. */ function getPendingTopup( RewardServiceState storage _self ) internal view returns(uint256 _pendingTopupWei) { return _self.inflationTopupRequestedWei.sub(_self.inflationTopupReceivedWei); } /** * @notice Initial a new reward service. * @dev Assume service is already instantiated. */ function initialize( RewardServiceState storage _self, IIInflationReceiver _inflationReceiver ) internal { _self.inflationReceiver = _inflationReceiver; _self.authorizedInflationWei = 0; _self.lastDailyAuthorizedInflationWei = 0; _self.inflationTopupRequestedWei = 0; _self.inflationTopupReceivedWei = 0; _self.inflationTopupWithdrawnWei = 0; } }
./contracts/inflation/lib/RewardServices.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../../utils/implementation/DateTimeLibrary.sol"; import "../implementation/Inflation.sol"; import "../interface/IIInflationReceiver.sol"; import "./RewardService.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; import "../interface/IIInflationSharingPercentageProvider.sol"; import "./RewardService.sol"; /** * @title Reward Services library * @notice A library to manage a collection of reward services, their associated totals, and to perform operations * that impact or involve the collection, such as calculating topup amounts across services. * @dev There are two concepts that are helpful to understand. A sharing percentage associates an inflation receiver * with a sharing percentage used to calculate percentage of authorized inflation a given reward contract * is entitled to receive for distributing rewards. A reward service is associtated to a topup configuration, which * dictates how much native token will be minted and sent for claiming reserves, and it stores totals for a given * inflation * receiver, for a given annum. **/ library RewardServices { using BokkyPooBahsDateTimeLibrary for uint256; using RewardService for RewardService.RewardServiceState; using SafeMath for uint256; using SafePct for uint256; /** * @dev `RewardServicesState` is state structure used by this library to manage * a collection of reward services and associated totals. */ struct RewardServicesState { // Collection of annums RewardService.RewardServiceState[] rewardServices; // Balances uint256 totalAuthorizedInflationWei; uint256 totalInflationTopupRequestedWei; uint256 totalInflationTopupReceivedWei; uint256 totalInflationTopupWithdrawnWei; } uint256 internal constant BIPS100 = 1e4; // 100% in basis points event RewardServiceDailyAuthorizedInflationComputed(IIInflationReceiver inflationReceiver, uint256 amountWei); event RewardServiceTopupRequestReceived(IIInflationReceiver inflationReceiver, uint256 amountWei); /** * @notice For all sharing percentages, compute authorized daily inflation for current cycle * and then allocate it across associated inflation receivers according to their sharing percentages, * updating reward service totals along the way. Finally, * set the daily authorized inflation for the given inflation receiver. * @param _totalRecognizedInflationWei The total recognized inflation across all annums. * @param _totalAuthorizedInflationWei The total authorized inflation across all annums. * @param _periodsRemaining The number of periods remaining in the current annum. * @param _sharingPercentages An array of inflation sharing percentages. * @return _amountAuthorizedWei The inflation authorized for this cycle. * @dev This method requires totals across all annums so as to continually calculate * the amount remaining to be authorized regardless of timing slippage between annums should it * occur. */ function authorizeDailyInflation( RewardServicesState storage _self, uint256 _totalRecognizedInflationWei, uint256 _totalAuthorizedInflationWei, uint256 _periodsRemaining, SharingPercentage[] memory _sharingPercentages ) internal returns(uint256 _amountAuthorizedWei) { // If there are no sharing percentages, then there is nothing to authorize. if (_sharingPercentages.length == 0) { _amountAuthorizedWei = 0; return _amountAuthorizedWei; } // Compute amount to allocate uint256 amountToAuthorizeRemaingWei = _totalRecognizedInflationWei .sub(_totalAuthorizedInflationWei) .div(_periodsRemaining); // Set up return value with amount authorized _amountAuthorizedWei = amountToAuthorizeRemaingWei; // Accumulate authorized total...note that this total is for a given annum, for a given service _self.totalAuthorizedInflationWei = _self.totalAuthorizedInflationWei.add(amountToAuthorizeRemaingWei); // Start with total bips in denominator uint256 divisorRemaining = BIPS100; // Loop over sharing percentages for (uint256 i; i < _sharingPercentages.length; i++) { // Compute the amount to authorize for a given service uint256 toAuthorizeWei = amountToAuthorizeRemaingWei.mulDiv( _sharingPercentages[i].percentBips, divisorRemaining ); // Reduce the numerator by amount just computed amountToAuthorizeRemaingWei = amountToAuthorizeRemaingWei.sub(toAuthorizeWei); // Reduce the divisor by the bips just allocated divisorRemaining = divisorRemaining.sub(_sharingPercentages[i].percentBips); // Try to find a matching reward service for the given sharing percentage. // New sharing percentages can be added at any time. And if one gets removed, // we don't remove that reward service for a given annum, since its total still // remains applicable. ( bool found, uint256 rewardServiceIndex ) = findRewardService(_self, _sharingPercentages[i].inflationReceiver); if (found) { // Get the existing reward service RewardService.RewardServiceState storage rewardService = _self.rewardServices[rewardServiceIndex]; // Accumulate the amount authorized for the service rewardService.addAuthorizedInflation(toAuthorizeWei); } else { // Initialize a new reward service RewardService.RewardServiceState storage rewardService = _self.rewardServices.push(); rewardService.initialize(_sharingPercentages[i].inflationReceiver); // Accumulate the amount authorized for the service rewardService.addAuthorizedInflation(toAuthorizeWei); } // Signal the inflation receiver of the reward service (the actual rewarding contract) // with amount just authorized. _sharingPercentages[i].inflationReceiver.setDailyAuthorizedInflation(toAuthorizeWei); emit RewardServiceDailyAuthorizedInflationComputed( _sharingPercentages[i].inflationReceiver, toAuthorizeWei); } } /** * @notice Given topup configurations as maintained by an instantiated Inflation contract, compute * the topup minting requests needed to topup reward contracts with native token reserves to satisfy claim * requests. * @param _inflation The Inflation contract holding the topup configurations. * @return _topupRequestWei The topup request to mint native tokens across reward services for this cycle. */ function computeTopupRequest( RewardServicesState storage _self, Inflation _inflation ) internal returns (uint256 _topupRequestWei) { for (uint256 i; i < _self.rewardServices.length; i++) { TopupConfiguration memory topupConfiguration = _inflation.getTopupConfiguration(_self.rewardServices[i].inflationReceiver); _topupRequestWei = _topupRequestWei.add(_self.rewardServices[i].computeTopupRequest(topupConfiguration)); } _self.totalInflationTopupRequestedWei = _self.totalInflationTopupRequestedWei.add(_topupRequestWei); // Make sure topup requested never exceeds the amount authorized assert(_self.totalInflationTopupRequestedWei <= _self.totalAuthorizedInflationWei); } /** * @notice Given an inflation receiver, return the index of the associated reward service. * @param _inflationReceiver The inflation receiver. * @return _found True if the reward service was found. * @return _index The index on the rewardServices array of the found service. Index is undefined * if the reward service was not found. */ function findRewardService( RewardServicesState storage _self, IIInflationReceiver _inflationReceiver ) internal view returns(bool _found, uint256 _index) { // The number of these is expected to be low. _found = false; for (uint256 i; i < _self.rewardServices.length; i++) { if (address(_self.rewardServices[i].inflationReceiver) == address(_inflationReceiver)) { _index = i; _found = true; break; } } } /** * @notice Receive a topup request of minted native tokens and disburse amongst requestors. * @return _amountPostedWei The total amount of native tokens funded. * @dev Assume value is siting in Inflation contract waiting to be posted and transmitted. * This function is atomic, so if for some reason not enough native tokens got minted, this * function will fail until all topup requests can be satisfied. */ function receiveTopupRequest( RewardServicesState storage _self ) internal returns(uint256 _amountPostedWei) { // Spin through all reward services for (uint256 i; i < _self.rewardServices.length; i++) { // Get the pending topup for the service uint256 pendingTopupWei = _self.rewardServices[i].getPendingTopup(); // Accumulate topup received _self.rewardServices[i].addTopupReceived(pendingTopupWei); _self.totalInflationTopupReceivedWei = _self.totalInflationTopupReceivedWei.add(pendingTopupWei); // Transfer topup to rewarding service contract _self.rewardServices[i].inflationReceiver.receiveInflation{ value: pendingTopupWei }(); // Accumulate topup withdrawn _self.rewardServices[i].addTopupWithdrawn(pendingTopupWei); _self.totalInflationTopupWithdrawnWei = _self.totalInflationTopupWithdrawnWei.add(pendingTopupWei); // Accumulate amount posted _amountPostedWei = _amountPostedWei.add(pendingTopupWei); emit RewardServiceTopupRequestReceived(_self.rewardServices[i].inflationReceiver, pendingTopupWei); } } }
./contracts/userInterfaces/IGovernanceSettings.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; /** * A special contract that holds Flare governance address. * This contract enables updating governance address and timelock only by hard forking the network, * meaning only by updating validator code. */ interface IGovernanceSettings { /** * Get the governance account address. * The governance address can only be changed by a hardfork. */ function getGovernanceAddress() external view returns (address); /** * Get the time in seconds that must pass between a governance call and execution. * The timelock value can only be changed by a hardfork. */ function getTimelock() external view returns (uint256); /** * Get the addresses of the accounts that are allowed to execute the timelocked governance calls * once the timelock period expires. * Executors can be changed without a hardfork, via a normal governance call. */ function getExecutors() external view returns (address[] memory); /** * Check whether an address is one of the executors. */ function isExecutor(address _address) external view returns (bool); }
./contracts/utils/implementation/DateTimeLibrary.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; // ---------------------------------------------------------------------------- // BokkyPooBah's DateTime Library v1.01 // // A gas-efficient Solidity date and time library // // https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary // // Tested date range 1970/01/01 to 2345/12/31 // // Conventions: // Unit | Range | Notes // :-------- |:-------------:|:----- // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC // year | 1970 ... 2345 | // month | 1 ... 12 | // day | 1 ... 31 | // hour | 0 ... 23 | // minute | 0 ... 59 | // second | 0 ... 59 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. // ---------------------------------------------------------------------------- library BokkyPooBahsDateTimeLibrary { uint public constant SECONDS_PER_DAY = 24 * 60 * 60; uint public constant SECONDS_PER_HOUR = 60 * 60; uint public constant SECONDS_PER_MINUTE = 60; int public constant OFFSET19700101 = 2440588; uint public constant DOW_MON = 1; uint public constant DOW_TUE = 2; uint public constant DOW_WED = 3; uint public constant DOW_THU = 4; uint public constant DOW_FRI = 5; uint public constant DOW_SAT = 6; uint public constant DOW_SUN = 7; // ------------------------------------------------------------------------ // Calculate the number of days from 1970/01/01 to year/month/day using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and subtracting the offset 2440588 so that 1970/01/01 is day 0 // // days = day // - 32075 // + 1461 * (year + 4800 + (month - 14) / 12) / 4 // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 // - offset // ------------------------------------------------------------------------ function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { require(year >= 1970); int _year = int(year); int _month = int(month); int _day = int(day); int __days = _day - 32075 + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 - OFFSET19700101; _days = uint(__days); } // ------------------------------------------------------------------------ // Calculate year/month/day from the number of days since 1970/01/01 using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and adding the offset 2440588 so that 1970/01/01 is day 0 // // int tempL = days + 68569 + offset // int tempN = 4 * tempL / 146097 // tempL = tempL - (146097 * tempN + 3) / 4 // year = 4000 * (tempL + 1) / 1461001 // tempL = tempL - 1461 * year / 4 + 31 // month = 80 * tempL / 2447 // dd = tempL - 2447 * month / 80 // tempL = month / 11 // month = month + 2 - 12 * tempL // year = 100 * (tempN - 49) + year + tempL // ------------------------------------------------------------------------ //solhint-disable max-line-length function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { int __days = int(_days); /* solhint-disable var-name-mixedcase */ int L = __days + 68569 + OFFSET19700101; int N = 4 * L / 146097; /* solhint-enable var-name-mixedcase */ L = L - (146097 * N + 3) / 4; int _year = 4000 * (L + 1) / 1461001; L = L - 1461 * _year / 4 + 31; int _month = 80 * L / 2447; int _day = L - 2447 * _month / 80; L = _month / 11; _month = _month + 2 - 12 * L; _year = 100 * (N - 49) + _year + L; year = uint(_year); month = uint(_month); day = uint(_day); } function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; } function timestampFromDateTime( uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; } function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function timestampToDateTime(uint timestamp) internal pure returns ( uint year, uint month, uint day, uint hour, uint minute, uint second) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; secs = secs % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; second = secs % SECONDS_PER_MINUTE; } function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { if (year >= 1970 && month > 0 && month <= 12) { uint daysInMonth = _getDaysInMonth(year, month); if (day > 0 && day <= daysInMonth) { valid = true; } } } function isValidDateTime( uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { if (isValidDate(year, month, day)) { if (hour < 24 && minute < 60 && second < 60) { valid = true; } } } function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); leapYear = _isLeapYear(year); } function _isLeapYear(uint year) internal pure returns (bool leapYear) { leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); } function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { weekDay = getDayOfWeek(timestamp) <= DOW_FRI; } function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; } function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); daysInMonth = _getDaysInMonth(year, month); } function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { daysInMonth = 31; } else if (month != 2) { daysInMonth = 30; } else { daysInMonth = _isLeapYear(year) ? 29 : 28; } } // 1 = Monday, 7 = Sunday function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { uint _days = timestamp / SECONDS_PER_DAY; dayOfWeek = (_days + 3) % 7 + 1; } function getYear(uint timestamp) internal pure returns (uint year) { (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getMonth(uint timestamp) internal pure returns (uint month) { (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getDay(uint timestamp) internal pure returns (uint day) { (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getHour(uint timestamp) internal pure returns (uint hour) { uint secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; } function getMinute(uint timestamp) internal pure returns (uint minute) { uint secs = timestamp % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; } function getSecond(uint timestamp) internal pure returns (uint second) { second = timestamp % SECONDS_PER_MINUTE; } function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); year += _years; uint daysInMonth = _getDaysInMonth(year, month); // When adding a year to feb 29th if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); month += _months; year += (month - 1) / 12; month = (month - 1) % 12 + 1; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _days * SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; require(newTimestamp >= timestamp); } function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; require(newTimestamp >= timestamp); } function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _seconds; require(newTimestamp >= timestamp); } /** * @dev removed since it can be a cause of errors * adding and removing a year may not end up on the same point in time */ // function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { // (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); // year -= _years; // uint daysInMonth = _getDaysInMonth(year, month); // if (day > daysInMonth) { // day = daysInMonth; // } // newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; // require(newTimestamp <= timestamp); // } /** * @dev removed since it can be a cause of errors * adding and removing a month may not end up on the same point in time * Intendet functionality: * 31.5 + 1 month => 30.6 * 30.6 - 1 month => 30.5 * this may cause problems */ // function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { // (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); // uint yearMonth = year * 12 + (month - 1) - _months; // year = yearMonth / 12; // month = yearMonth % 12 + 1; // uint daysInMonth = _getDaysInMonth(year, month); // if (day > daysInMonth) { // day = daysInMonth; // } // newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; // require(newTimestamp <= timestamp); // } function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _days * SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; require(newTimestamp <= timestamp); } function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; require(newTimestamp <= timestamp); } function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _seconds; require(newTimestamp <= timestamp); } function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { require(fromTimestamp <= toTimestamp); (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _years = toYear - fromYear; } function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { require(fromTimestamp <= toTimestamp); (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; } function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { require(fromTimestamp <= toTimestamp); _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; } function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { require(fromTimestamp <= toTimestamp); _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; } function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { require(fromTimestamp <= toTimestamp); _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; } function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { require(fromTimestamp <= toTimestamp); _seconds = toTimestamp - fromTimestamp; } function getDaysInYear(uint timestamp) internal pure returns (uint daysInYear) { return isLeapYear(timestamp) ? 366 : 365; } }
./contracts/utils/implementation/GovernedAndFlareDaemonized.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import { FlareDaemon } from "../../genesis/implementation/FlareDaemon.sol"; import { Governed } from "../../governance/implementation/Governed.sol"; contract GovernedAndFlareDaemonized is Governed { FlareDaemon public immutable flareDaemon; modifier onlyFlareDaemon () { require (msg.sender == address(flareDaemon), "only flare daemon"); _; } constructor(address _governance, FlareDaemon _flareDaemon) Governed(_governance) { require(address(_flareDaemon) != address(0), "flare daemon zero"); flareDaemon = _flareDaemon; } }
./contracts/utils/implementation/SafePct.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; /** * @dev Compute percentages safely without phantom overflows. * * Intermediate operations can overflow even when the result will always * fit into computed type. Developers usually * assume that overflows raise errors. `SafePct` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafePct { using SafeMath for uint256; /** * Requirements: * * - intermediate operations must revert on overflow */ function mulDiv(uint256 x, uint256 y, uint256 z) internal pure returns (uint256) { require(z > 0, "Division by zero"); if (x == 0) return 0; uint256 xy = x * y; if (xy / x == y) { // no overflow happened - same as in SafeMath mul return xy / z; } //slither-disable-next-line divide-before-multiply uint256 a = x / z; uint256 b = x % z; // x = a * z + b //slither-disable-next-line divide-before-multiply uint256 c = y / z; uint256 d = y % z; // y = c * z + d return (a.mul(c).mul(z)).add(a.mul(d)).add(b.mul(c)).add(b.mul(d).div(z)); } }
@openzeppelin/contracts/math/SafeMath.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ 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; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
@openzeppelin/contracts/utils/SafeCast.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits"); return int128(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits"); return int64(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits"); return int32(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits"); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits. * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits"); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_flareDaemon","internalType":"contract FlareDaemon"},{"type":"address","name":"_addressUpdater","internalType":"address"},{"type":"uint256","name":"_rewardEpochStartTs","internalType":"uint256"}]},{"type":"event","name":"GovernanceCallTimelocked","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256","indexed":false},{"type":"bytes","name":"encodedCall","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceInitialised","inputs":[{"type":"address","name":"initialGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernedProductionModeEntered","inputs":[{"type":"address","name":"governanceSettings","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"InflationAllocationSet","inputs":[{"type":"address","name":"inflationAllocation","internalType":"contract IIInflationAllocation","indexed":false}],"anonymous":false},{"type":"event","name":"InflationAuthorized","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MintingReceived","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"selfDestructAmountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NewAnnumInitialized","inputs":[{"type":"uint256","name":"startTimeStamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"endTimeStamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"inflatableSupplyWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"recognizedInflationWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalAuthorizedInflationWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalInflationTopupRequestedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalInflationTopupReceivedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalInflationTopupWithdrawnWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardServiceDailyAuthorizedInflationComputed","inputs":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardServiceTopupComputed","inputs":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardServiceTopupRequestReceived","inputs":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SupplySet","inputs":[{"type":"address","name":"oldSupply","internalType":"contract IISupply","indexed":false},{"type":"address","name":"newSupply","internalType":"contract IISupply","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallCanceled","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallExecuted","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TopupConfigurationSet","inputs":[{"type":"tuple","name":"topupConfiguration","internalType":"struct TopupConfiguration","indexed":false,"components":[{"type":"uint8","name":"topupType","internalType":"enum TopupType"},{"type":"uint256","name":"topupFactorX100","internalType":"uint256"},{"type":"bool","name":"configured","internalType":"bool"}]}],"anonymous":false},{"type":"event","name":"TopupRequested","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"daemonize","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract FlareDaemon"}],"name":"flareDaemon","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_addressUpdater","internalType":"address"}],"name":"getAddressUpdater","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct InflationAnnum.InflationAnnumState","components":[{"type":"uint256","name":"recognizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"rewardServices","internalType":"struct RewardServices.RewardServicesState","components":[{"type":"tuple[]","name":"rewardServices","internalType":"struct RewardService.RewardServiceState[]","components":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver"},{"type":"uint256","name":"authorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupWithdrawnWei","internalType":"uint256"}]}]}],"name":"getAnnum","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"getContractName","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct InflationAnnum.InflationAnnumState","components":[{"type":"uint256","name":"recognizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"rewardServices","internalType":"struct RewardServices.RewardServicesState","components":[{"type":"tuple[]","name":"rewardServices","internalType":"struct RewardService.RewardServiceState[]","components":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver"},{"type":"uint256","name":"authorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupWithdrawnWei","internalType":"uint256"}]}]}],"name":"getCurrentAnnum","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_nextTopupTs","internalType":"uint256"}],"name":"getNextExpectedTopupTs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"tuple","name":"_topupConfiguration","internalType":"struct TopupConfiguration","components":[{"type":"uint8","name":"topupType","internalType":"enum TopupType"},{"type":"uint256","name":"topupFactorX100","internalType":"uint256"},{"type":"bool","name":"configured","internalType":"bool"}]}],"name":"getTopupConfiguration","inputs":[{"type":"address","name":"_inflationReceiver","internalType":"contract IIInflationReceiver"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_totalAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationTopupWithdrawnWei","internalType":"uint256"},{"type":"uint256","name":"_totalRecognizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"_totalSelfDestructReceivedWei","internalType":"uint256"}],"name":"getTotals","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IGovernanceSettings"}],"name":"governanceSettings","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIInflationAllocation"}],"name":"inflationAllocation","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_initialGovernance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastAuthorizationTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"productionMode","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"receiveMinting","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochStartTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochStartedTs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTopupConfiguration","inputs":[{"type":"address","name":"_inflationReceiver","internalType":"contract IIInflationReceiver"},{"type":"uint8","name":"_topupType","internalType":"enum TopupType"},{"type":"uint256","name":"_topupFactorX100","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IISupply"}],"name":"supply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"switchToFallbackMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"switchToProductionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256"},{"type":"bytes","name":"encodedCall","internalType":"bytes"}],"name":"timelockedCalls","inputs":[{"type":"bytes4","name":"","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSelfDestructReceivedWei","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateContractAddresses","inputs":[{"type":"bytes32[]","name":"_contractNameHashes","internalType":"bytes32[]"},{"type":"address[]","name":"_contractAddresses","internalType":"address[]"}]}]
Contract Creation Code
0x60c06040523480156200001157600080fd5b50604051620038fa380380620038fa833981016040819052620000349162000206565b81848481806001600160a01b03811615620000545762000054816200011f565b506001600160a01b038116620000a4576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b506001600160a01b038116620000f5576040805162461bcd60e51b8152602060048201526011602482015270666c617265206461656d6f6e207a65726f60781b604482015290519081900360640190fd5b60601b6001600160601b031916608052506200011181620001e2565b5060a0525062000278915050565b600054600160a01b900460ff16156200017f576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600080600080608085870312156200021c578384fd5b845162000229816200025f565b60208601519094506200023c816200025f565b60408601519093506200024f816200025f565b6060959095015193969295505050565b6001600160a01b03811681146200027557600080fd5b50565b60805160601c60a051613642620002b860003980610b5d5280611274525080610af55280610df052806111a552806113bb528061151152506136426000f3fe60806040526004361061019c5760003560e01c80639d6a890f116100ec578063e17f212e1161008a578063f5a9838311610064578063f5a9838314610430578063f5f5ba7214610445578063f639c12c14610467578063f64cee611461047c5761019c565b8063e17f212e146103f1578063e22fdece14610406578063f3f8dcf91461041b5761019c565b8063b8cca0cf116100c6578063b8cca0cf1461039d578063c39049e4146103b2578063c611c2c5146103d4578063c9d3dc87146103dc5761019c565b80639d6a890f14610348578063a107753214610368578063b00c0b761461037d5761019c565b806362354e03116101595780636e61ab96116101335780636e61ab96146102be57806372993615146102de57806374e6310e146102f357806384e10a90146103215761019c565b806362354e031461026757806367fc40291461027c5780636d0e8c341461029c5761019c565b8063047fc9aa146101a157806333ed77cc146101cc5780634b13e872146101ee5780635267a15d1461021b5780635aa6e675146102305780635ff2707914610245575b600080fd5b3480156101ad57600080fd5b506101b661049c565b6040516101c39190613241565b60405180910390f35b3480156101d857600080fd5b506101e16104ab565b6040516101c391906133e4565b3480156101fa57600080fd5b5061020e610209366004612f46565b6104b1565b6040516101c39190613381565b34801561022757600080fd5b506101b6610595565b34801561023c57600080fd5b506101b66105ba565b34801561025157600080fd5b506102656102603660046130ea565b610650565b005b34801561027357600080fd5b506101b66109a5565b34801561028857600080fd5b506102656102973660046130ea565b6109b0565b3480156102a857600080fd5b506102b1610a98565b6040516101c39190613255565b3480156102ca57600080fd5b506102656102d9366004613112565b610eb9565b3480156102ea57600080fd5b506101e1611020565b3480156102ff57600080fd5b5061031361030e3660046130ea565b611026565b6040516101c39291906133ed565b34801561032d57600080fd5b506103366110cc565b6040516101c39695949392919061341c565b34801561035457600080fd5b50610265610363366004612f46565b6110ea565b34801561037457600080fd5b506101b66111a3565b34801561038957600080fd5b50610265610398366004612f62565b6111c7565b3480156103a957600080fd5b506101e1611272565b3480156103be57600080fd5b506103c7611296565b6040516101c391906132a6565b6102656113b0565b3480156103e857600080fd5b506101e16114ee565b3480156103fd57600080fd5b506102b16114f4565b34801561041257600080fd5b506102b1611504565b34801561042757600080fd5b506101b661157d565b34801561043c57600080fd5b5061026561158c565b34801561045157600080fd5b5061045a611646565b6040516101c39190613293565b34801561047357600080fd5b506101e1611669565b34801561048857600080fd5b506103c76104973660046131b8565b61167c565b6003546001600160a01b031681565b600e5481565b6104b9612d76565b60408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b03821661050e5760405162461bcd60e51b81526004016105059190613293565b60405180910390fd5b506001600160a01b0383166000908152600c60205260409020600281015460ff1661055557805460ff19908116825560786001808401919091556002830180549092161790555b8054839060ff16600181111561056757fe5b9081600181111561057457fe5b905250600181015460208401526002015460ff161515604083015250919050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166105dd576000546001600160a01b031661064a565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561061d57600080fd5b505afa158015610631573d6000803e3d6000fd5b505050506040513d602081101561064757600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561069457600080fd5b505afa1580156106a8573d6000803e3d6000fd5b505050506040513d60208110156106be57600080fd5b5051610701576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b031981166000908152600160205260409020805461076d576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156107c3576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561085d5780601f106108325761010080835404028352916020019161085d565b820191906000526020600020905b81548152906001019060200180831161084057829003601f168201915b5050506001600160e01b03198616600090815260016020819052604082208281559495509092506108919150830182612d98565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106108d95780518252601f1990920191602091820191016108ba565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461093b576040519150601f19603f3d011682016040523d82523d6000602084013e610940565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a161099f81611798565b50505050565b60076001609c1b0181565b6109b86117b5565b6001600160e01b03198116600090815260016020526040902054610a23576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610a9390830182612d98565b505050565b60035460408051808201909152600c81526b06164647265737320697320360a41b60208201526000916001600160a01b03169081610ae95760405162461bcd60e51b81526004016105059190613293565b50336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b5b576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b7f0000000000000000000000000000000000000000000000000000000000000000421015610b8c5760019150610eb5565b600e54610b985742600e555b610ba26004611816565b610bb457610baf4261181a565b610be3565b6000610bc06004611b65565b60020154905080421115610be157610be1610bdc826001611bda565b61181a565b505b600b544290610bf59062015180611bda565b11610eb05742600b819055506000610c9c42600260009054906101000a90046001600160a01b03166001600160a01b031663c853b8d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610c5757600080fd5b505af1158015610c6b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c939190810190613019565b60049190611c3d565b90507fe69ea09c0c2d88b5a023a23e65e8ffeb65667d6b7b4076cbee9ba25f5450235581604051610ccd91906133e4565b60405180910390a1600354604051630512107160e51b81526001600160a01b039091169063a2420e2090610d059084906004016133e4565b600060405180830381600087803b158015610d1f57600080fd5b505af1925050508015610d30575060015b610d9357610d3c6134c2565b80610d475750610d61565b8060405162461bcd60e51b81526004016105059190613293565b6040518060600160405280603c81526020016135d1603c913960405162461bcd60e51b81526004016105059190613293565b6000610da0600430611c9f565b90507f1f0936062e6ce780790714a1ec5787d290675660a8566059ac9d6cfb2a336eec81604051610dd191906133e4565b60405180910390a160405163074ef3eb60e51b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e9de7d6090610e259084906004016133e4565b600060405180830381600087803b158015610e3f57600080fd5b505af1925050508015610e50575060015b610ead57610e5c6134c2565b80610d475750604080518082018252601d81527f756e6b6e6f776e206572726f722e20726571756573744d696e74696e670000006020820152905162461bcd60e51b81526105059190600401613293565b50505b600191505b5090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015283906001600160a01b038216610f055760405162461bcd60e51b81526004016105059190613293565b50600054600160b01b900460ff1680610f285750600054600160a81b900460ff16155b1561101557610f35611ce7565b6000836001811115610f4357fe5b1415610f8c57604080518082019091526009815268746f707570206c6f7760b81b602082015260648311610f8a5760405162461bcd60e51b81526004016105059190613293565b505b6001600160a01b0384166000908152600c6020526040902080548490829060ff191660018381811115610fbb57fe5b0217905550600180820184905560028201805460ff191690911790556040517fcf085312d79a75faa5f1b9f6bec58a64813338f5e5e5759573cab22c6da2d25b906110079083906133b0565b60405180910390a15061099f565b61099f600036611d1c565b600d5481565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156110c25780601f10611097576101008083540402835291602001916110c2565b820191906000526020600020905b8154815290600101906020018083116110a557829003601f168201915b5050505050905082565b600754600854600954600a54600654600d5494959394929391929091565b600054600160a01b900460ff1615611140576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b6111cf610595565b6001600160a01b0316336001600160a01b03161461122b576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b61126461125f83836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250611e9f565b611fce565b61126e8282611ff2565b5050565b7f000000000000000000000000000000000000000000000000000000000000000081565b61129e612ddc565b6112a86004611b65565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b828210156113775760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611306565b50505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081525050905090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611421576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b600061142d6004612105565b9050600061143961216e565b90506000611447478361218f565b9050801561146057600d5461145c9082611bda565b600d555b7f992ba5c7b7d6602101783b4d28d0b93011fb883039e68c729b933bf711678627838260405161149192919061340e565b60405180910390a1505050476114a561216e565b146040518060400160405280600e81526020016d6f7574206f662062616c616e636560901b815250906114eb5760405162461bcd60e51b81526004016105059190613293565b50565b600b5481565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611577576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b6002546001600160a01b031681565b6115946117b5565b600054600160a81b900460ff16156115f3576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600981526824b7333630ba34b7b760b91b602082015290565b600b5460009061064a9062015180611bda565b611684612ddc565b61168f6004836121ec565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561175e5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a083015290835290920191016116ed565b5050509082525060018201546020820152600282015460408201526003820154606082015260049091015460809091015290525092915050565b3d604051818101604052816000823e82156117b1578181f35b8181fd5b6117bd6105ba565b6001600160a01b0316336001600160a01b031614611814576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b5490565b600360009054906101000a90046001600160a01b03166001600160a01b0316633c8c461c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561186a57600080fd5b505af115801561187e573d6000803e3d6000fd5b505050506000600360009054906101000a90046001600160a01b03166001600160a01b0316631b73b4cb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156118d257600080fd5b505afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a91906131d0565b9050600260009054906101000a90046001600160a01b03166001600160a01b031663981940296040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561195c57600080fd5b505af192505050801561198c575060408051601f3d908101601f19168201909252611989918101906131d0565b60015b6119d0576119986134c2565b80610d47575060405180606001604052806026815260200161358a6026913960405162461bcd60e51b81526004016105059190613293565b6119dd600484848461225e565b5060006119ea6004611b65565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611ab95760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611a48565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090507f677db469fe5eaf40f0415f5433ebc8ebe9ac089662feca0280495fb4c96da29181602001518260400151848460000151856060015160200151866060015160400151876060015160600151886060015160800151604051611b58989796959493929190613444565b60405180910390a1505050565b600080611b7183611816565b11604051806040016040528060088152602001676e6f20616e6e756d60c01b81525090611bb15760405162461bcd60e51b81526004016105059190613293565b5081600001826001015481548110611bc557fe5b90600052602060002090600802019050919050565b600082820183811015611c34576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600080611c4985611b65565b60028601546003870154919250611c7191611c64848861231e565b600385019291908761233d565b6003860154909250611c839083611bda565b6003860181905560028601541015611c9757fe5b509392505050565b600080611cab84611b65565b9050611cba600382018461258e565b6004850154909250611ccc9083611bda565b6004850181905560038501541015611ce057fe5b5092915050565b600054600160b01b900460ff1615611d1457333014611d0257fe5b6000805460ff60b01b19169055611814565b6118146117b5565b611d246117b5565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6c57600080fd5b505afa158015611d80573d6000803e3d6000fd5b505050506040513d6020811015611d9657600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b03198616815260016020818152604090922084518155848301518051919450611e1a93928501920190612e09565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b83811015611ee3578181015183820152602001611ecb565b50505050905090810190601f168015611f105780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b8651811015611f7857868181518110611f4657fe5b6020026020010151831415611f7057858181518110611f6157fe5b60200260200101519150611f78565b600101611f31565b506001600160a01b038116611fc3576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b9150505b9392505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600061201d838360405180604001604052806006815260200165537570706c7960d01b815250611e9f565b6003546040519192507f9a9b245c8db671c90d6db95f7ff0c18c15378a1d55ee4aea21759be8ad27d30e9161205d916001600160a01b0316908490613279565b60405180910390a1600380546001600160a01b0319166001600160a01b03831617905560408051808201909152601381527224b7333630ba34b7b720b63637b1b0ba34b7b760691b60208201526120b79084908490611e9f565b600280546001600160a01b0319166001600160a01b0392831617908190556040517f53cd61e1fdebbc2af2597f77a6a3681c1abbd8771874cc85cf65e035cf85b2af92611b58921690613241565b60008061211183611b65565b905061211f816003016126b2565b60058401549092506121319083611bda565b600584018190556004840154101561214557fe5b60068301546121549083611bda565b600684018190556005840154101561216857fe5b50919050565b600d54600a5460095460009261064a9290916121899161218f565b90611bda565b6000828211156121e6576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006121f783611816565b8210604051806040016040528060088152602001676e6f20616e6e756d60c01b815250906122385760405162461bcd60e51b81526004016105059190613293565b5082600001828154811061224857fe5b9060005260206000209060080201905092915050565b600061226985611816565b11156122c05761227884611b65565b60020154831160405180604001604052806009815260200168746f6f206561726c7960b81b815250906122be5760405162461bcd60e51b81526004016105059190613293565b505b83546001810185556000858152602090206008909102016122e38185858561285c565b805460028601546122f391611bda565b60028601558454600110156123175760018581015461231191611bda565b60018601555b5050505050565b6000826002015482111561232e57fe5b611c3460016121898585612886565b600081516000141561235157506000612585565b600061236784612361888861218f565b906128b2565b600188015490925082915061237c9082611bda565b600188015561271060005b84518110156125815760006123be8683815181106123a157fe5b60200260200101516020015184866129199092919063ffffffff16565b90506123ca848261218f565b93506123f68683815181106123db57fe5b6020026020010151602001518461218f90919063ffffffff16565b925060008061241c8c89868151811061240b57fe5b602002602001015160000151612a19565b9150915081156124605760008c600001828154811061243757fe5b9060005260206000209060060201905061245a8482612a7c90919063ffffffff16565b506124b1565b8b54600181018d5560008d8152602090208951600690920201906124a5908a908790811061248a57fe5b60200260200101516000015182612a9890919063ffffffff16565b6124af8185612a7c565b505b8784815181106124bd57fe5b6020026020010151600001516001600160a01b031663e2739563846040518263ffffffff1660e01b81526004016124f491906133e4565b600060405180830381600087803b15801561250e57600080fd5b505af1158015612522573d6000803e3d6000fd5b505050507fea9b87b57d7b678dd3c9da933ff547ad63395e04ee46cd57894c7b53618dc39a88858151811061255357fe5b6020026020010151600001518460405161256e929190613260565b60405180910390a1505050600101612387565b5050505b95945050505050565b6000805b835481101561268e576000836001600160a01b0316634b13e8728660000184815481106125bb57fe5b60009182526020909120600690910201546040516001600160e01b031960e084901b1681526125f6916001600160a01b031690600401613241565b606060405180830381600087803b15801561261057600080fd5b505af1158015612624573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126489190613152565b905061268361267c8287600001858154811061266057fe5b9060005260206000209060060201612ad990919063ffffffff16565b8490611bda565b925050600101612592565b50600283015461269e9082611bda565b6002840181905560018401541015611c3757fe5b6000805b82548110156121685760006126e68460000183815481106126d357fe5b9060005260206000209060060201612c2d565b9050612717818560000184815481106126fb57fe5b9060005260206000209060060201612c4a90919063ffffffff16565b60038401546127269082611bda565b6003850155835484908390811061273957fe5b60009182526020822060069091020154604080516306201f1d60e01b815290516001600160a01b03909216926306201f1d928592600480820193929182900301818588803b15801561278a57600080fd5b505af115801561279e573d6000803e3d6000fd5b50505050506127d2818560000184815481106127b657fe5b9060005260206000209060060201612c6590919063ffffffff16565b60048401546127e19082611bda565b60048501556127f08382611bda565b92507f4839bc860ac633cfbce1fe18dc3c135733eca7b2dc8ed40e6e6b713a431bcf4484600001838154811061282257fe5b600091825260209091206006909102015460405161284b916001600160a01b0316908490613260565b60405180910390a1506001016126b6565b6001840183905561286d8282612c80565b845561287883612caf565b846002018190555050505050565b6002820154600090808311156128a0576000915050611c37565b6128aa8382612cc7565b915050611c37565b6000808211612908576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161291157fe5b049392505050565b6000808211612962576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b8361296f57506000611fc7565b8383028385828161297c57fe5b0414156129955782818161298c57fe5b04915050611fc7565b60008386816129a057fe5b04905060008487816129ae57fe5b06905060008587816129bc57fe5b04905060008688816129ca57fe5b069050612a0c6129de886123618685612ce2565b6121896129eb8686612ce2565b6121896129f88987612ce2565b6121898d612a068c8b612ce2565b90612ce2565b9998505050505050505050565b600080805b8454811015612a7457836001600160a01b0316856000018281548110612a4057fe5b60009182526020909120600690910201546001600160a01b03161415612a6c5780915060019250612a74565b600101612a1e565b509250929050565b6001820154612a8b9082611bda565b6001830155600290910155565b81546001600160a01b0319166001600160a01b0391909116178155600060018201819055600282018190556003820181905560048201819055600590910155565b81546000906001600160a01b0316318183516001811115612af657fe5b1415612b975760208301516002850154600091612b1591906064612919565b9050600082821115612b2e57612b2b828461218f565b90505b6000612b3987612c2d565b905081811115612b4c5760009450612b59565b612b56828261218f565b94505b6000612b808860040154612b7a848b6001015461218f90919063ffffffff16565b9061218f565b905080861115612b8e578095505b50505050612bcc565b600183516001811115612ba657fe5b1415612bc65760038401546001850154612bbf9161218f565b9150612bcc565b60009150fe5b6003840154612bdb9083611bda565b600385015583546040517f9145b1e2df1630c4e7b11419b36afb9de07a4dc780726dfa970f265b1d627ad791612c1e916001600160a01b03909116908590613260565b60405180910390a15092915050565b6000611c378260040154836003015461218f90919063ffffffff16565b6004820154612c599082611bda565b82600401819055505050565b6005820154612c749082611bda565b82600501819055505050565b6000611c34612c9384846201d4c0612919565b612caa6b1027e72f1f12813088000000600c6128b2565b612d3b565b6000611c376001612cc184601e612d51565b90612d66565b600081831115612cd657600080fd5b62015180838303612911565b600082612cf157506000611c37565b82820282848281612cfe57fe5b0414611c345760405162461bcd60e51b81526004018080602001828103825260218152602001806135b06021913960400191505060405180910390fd5b6000818310612d4a5781611c34565b5090919050565b620151808102820182811015611c3757600080fd5b80820382811115611c3757600080fd5b6040805160608101909152806000815260006020820181905260409091015290565b50805460018160011615610100020316600290046000825580601f10612dbe57506114eb565b601f0160209004906000526020600020908101906114eb9190612e8d565b6040518060800160405280600081526020016000815260200160008152602001612e04612ea2565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612e3f5760008555612e85565b82601f10612e5857805160ff1916838001178555612e85565b82800160010185558215612e85579182015b82811115612e85578251825591602001919060010190612e6a565b50610eb59291505b5b80821115610eb55760008155600101612e8e565b6040518060a0016040528060608152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612ee1578081fd5b81356020612ef6612ef18361349e565b61347a565b8281528181019085830183850287018401881015612f12578586fd5b855b85811015612f39578135612f2781613567565b84529284019290840190600101612f14565b5090979650505050505050565b600060208284031215612f57578081fd5b8135611c3481613567565b60008060408385031215612f74578081fd5b823567ffffffffffffffff80821115612f8b578283fd5b818501915085601f830112612f9e578283fd5b81356020612fae612ef18361349e565b82815281810190858301838502870184018b1015612fca578788fd5b8796505b84871015612fec578035835260019690960195918301918301612fce565b5096505086013592505080821115613002578283fd5b5061300f85828601612ed1565b9150509250929050565b6000602080838503121561302b578182fd5b825167ffffffffffffffff80821115613042578384fd5b818501915085601f830112613055578384fd5b8151613063612ef18261349e565b818152848101908486016040808502870188018b1015613081578889fd5b8896505b848710156130db5780828c03121561309b578889fd5b805181810181811088821117156130ae57fe5b825282516130bb81613567565b815282890151898201528452600196909601959287019290810190613085565b50909998505050505050505050565b6000602082840312156130fb578081fd5b81356001600160e01b031981168114611c34578182fd5b600080600060608486031215613126578081fd5b833561313181613567565b925060208401356131418161357c565b929592945050506040919091013590565b600060608284031215613163578081fd5b6040516060810181811067ffffffffffffffff8211171561318057fe5b604052825161318e8161357c565b815260208381015190820152604083015180151581146131ac578283fd5b60408201529392505050565b6000602082840312156131c9578081fd5b5035919050565b6000602082840312156131e1578081fd5b5051919050565b60008151808452815b8181101561320d576020818501810151868301820152016131f1565b8181111561321e5782602083870101525b50601f01601f19169290920160200192915050565b6002811061323d57fe5b9052565b6001600160a01b0391909116815260200190565b901515815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b600060208252611c3460208301846131e8565b6000602080835260a0845182850152818501516040818187015280870151915060608281880152808801519250608080818901526101408801845186878b01528181518084526101608c01915089830193508a92505b8083101561335057835180516001600160a01b031683528a8101518b84015287810151888401528681015187840152858101518684015289015189830152928901926001929092019160c0909101906132fc565b509786015160c08b015250509183015160e08801528201516101008701520151610120909401939093529392505050565b6000606082019050613394828451613233565b6020830151602083015260408301511515604083015292915050565b60006060820190506133c68260ff855416613233565b6001830154602083015260029092015460ff16151560409091015290565b90815260200190565b60008382526040602083015261340660408301846131e8565b949350505050565b918252602082015260400190565b958652602086019490945260408501929092526060840152608083015260a082015260c00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405181810167ffffffffffffffff8111828210171561349657fe5b604052919050565b600067ffffffffffffffff8211156134b257fe5b5060209081020190565b60e01c90565b600060443d10156134d25761064d565b600481823e6308c379a06134e682516134bc565b146134f05761064d565b6040513d600319016004823e80513d67ffffffffffffffff8160248401118184111715613520575050505061064d565b8284019250825191508082111561353a575050505061064d565b503d830160208284010111156135525750505061064d565b601f01601f1916810160200160405291505090565b6001600160a01b03811681146114eb57600080fd5b600281106114eb57600080fdfe756e6b6e6f776e206572726f722e20676574416e6e75616c50657263656e7461676542697073536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77756e6b6e6f776e206572726f722e20757064617465417574686f72697a6564496e666c6174696f6e416e6443697263756c6174696e67537570706c79a2646970667358221220af53d0910e3dbc2ae5a50387c42e79d3b6aaabbc6b4641120525a0dfad5d8f4f64736f6c634300070600330000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b0000000000000000000000000000000000000000000000000000000062d1b8d6
Deployed ByteCode
0x60806040526004361061019c5760003560e01c80639d6a890f116100ec578063e17f212e1161008a578063f5a9838311610064578063f5a9838314610430578063f5f5ba7214610445578063f639c12c14610467578063f64cee611461047c5761019c565b8063e17f212e146103f1578063e22fdece14610406578063f3f8dcf91461041b5761019c565b8063b8cca0cf116100c6578063b8cca0cf1461039d578063c39049e4146103b2578063c611c2c5146103d4578063c9d3dc87146103dc5761019c565b80639d6a890f14610348578063a107753214610368578063b00c0b761461037d5761019c565b806362354e03116101595780636e61ab96116101335780636e61ab96146102be57806372993615146102de57806374e6310e146102f357806384e10a90146103215761019c565b806362354e031461026757806367fc40291461027c5780636d0e8c341461029c5761019c565b8063047fc9aa146101a157806333ed77cc146101cc5780634b13e872146101ee5780635267a15d1461021b5780635aa6e675146102305780635ff2707914610245575b600080fd5b3480156101ad57600080fd5b506101b661049c565b6040516101c39190613241565b60405180910390f35b3480156101d857600080fd5b506101e16104ab565b6040516101c391906133e4565b3480156101fa57600080fd5b5061020e610209366004612f46565b6104b1565b6040516101c39190613381565b34801561022757600080fd5b506101b6610595565b34801561023c57600080fd5b506101b66105ba565b34801561025157600080fd5b506102656102603660046130ea565b610650565b005b34801561027357600080fd5b506101b66109a5565b34801561028857600080fd5b506102656102973660046130ea565b6109b0565b3480156102a857600080fd5b506102b1610a98565b6040516101c39190613255565b3480156102ca57600080fd5b506102656102d9366004613112565b610eb9565b3480156102ea57600080fd5b506101e1611020565b3480156102ff57600080fd5b5061031361030e3660046130ea565b611026565b6040516101c39291906133ed565b34801561032d57600080fd5b506103366110cc565b6040516101c39695949392919061341c565b34801561035457600080fd5b50610265610363366004612f46565b6110ea565b34801561037457600080fd5b506101b66111a3565b34801561038957600080fd5b50610265610398366004612f62565b6111c7565b3480156103a957600080fd5b506101e1611272565b3480156103be57600080fd5b506103c7611296565b6040516101c391906132a6565b6102656113b0565b3480156103e857600080fd5b506101e16114ee565b3480156103fd57600080fd5b506102b16114f4565b34801561041257600080fd5b506102b1611504565b34801561042757600080fd5b506101b661157d565b34801561043c57600080fd5b5061026561158c565b34801561045157600080fd5b5061045a611646565b6040516101c39190613293565b34801561047357600080fd5b506101e1611669565b34801561048857600080fd5b506103c76104973660046131b8565b61167c565b6003546001600160a01b031681565b600e5481565b6104b9612d76565b60408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b03821661050e5760405162461bcd60e51b81526004016105059190613293565b60405180910390fd5b506001600160a01b0383166000908152600c60205260409020600281015460ff1661055557805460ff19908116825560786001808401919091556002830180549092161790555b8054839060ff16600181111561056757fe5b9081600181111561057457fe5b905250600181015460208401526002015460ff161515604083015250919050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166105dd576000546001600160a01b031661064a565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561061d57600080fd5b505afa158015610631573d6000803e3d6000fd5b505050506040513d602081101561064757600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561069457600080fd5b505afa1580156106a8573d6000803e3d6000fd5b505050506040513d60208110156106be57600080fd5b5051610701576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b031981166000908152600160205260409020805461076d576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156107c3576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561085d5780601f106108325761010080835404028352916020019161085d565b820191906000526020600020905b81548152906001019060200180831161084057829003601f168201915b5050506001600160e01b03198616600090815260016020819052604082208281559495509092506108919150830182612d98565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106108d95780518252601f1990920191602091820191016108ba565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461093b576040519150601f19603f3d011682016040523d82523d6000602084013e610940565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a161099f81611798565b50505050565b60076001609c1b0181565b6109b86117b5565b6001600160e01b03198116600090815260016020526040902054610a23576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610a9390830182612d98565b505050565b60035460408051808201909152600c81526b06164647265737320697320360a41b60208201526000916001600160a01b03169081610ae95760405162461bcd60e51b81526004016105059190613293565b50336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614610b5b576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b7f0000000000000000000000000000000000000000000000000000000062d1b8d6421015610b8c5760019150610eb5565b600e54610b985742600e555b610ba26004611816565b610bb457610baf4261181a565b610be3565b6000610bc06004611b65565b60020154905080421115610be157610be1610bdc826001611bda565b61181a565b505b600b544290610bf59062015180611bda565b11610eb05742600b819055506000610c9c42600260009054906101000a90046001600160a01b03166001600160a01b031663c853b8d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610c5757600080fd5b505af1158015610c6b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c939190810190613019565b60049190611c3d565b90507fe69ea09c0c2d88b5a023a23e65e8ffeb65667d6b7b4076cbee9ba25f5450235581604051610ccd91906133e4565b60405180910390a1600354604051630512107160e51b81526001600160a01b039091169063a2420e2090610d059084906004016133e4565b600060405180830381600087803b158015610d1f57600080fd5b505af1925050508015610d30575060015b610d9357610d3c6134c2565b80610d475750610d61565b8060405162461bcd60e51b81526004016105059190613293565b6040518060600160405280603c81526020016135d1603c913960405162461bcd60e51b81526004016105059190613293565b6000610da0600430611c9f565b90507f1f0936062e6ce780790714a1ec5787d290675660a8566059ac9d6cfb2a336eec81604051610dd191906133e4565b60405180910390a160405163074ef3eb60e51b81526001600160a01b037f0000000000000000000000001000000000000000000000000000000000000002169063e9de7d6090610e259084906004016133e4565b600060405180830381600087803b158015610e3f57600080fd5b505af1925050508015610e50575060015b610ead57610e5c6134c2565b80610d475750604080518082018252601d81527f756e6b6e6f776e206572726f722e20726571756573744d696e74696e670000006020820152905162461bcd60e51b81526105059190600401613293565b50505b600191505b5090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015283906001600160a01b038216610f055760405162461bcd60e51b81526004016105059190613293565b50600054600160b01b900460ff1680610f285750600054600160a81b900460ff16155b1561101557610f35611ce7565b6000836001811115610f4357fe5b1415610f8c57604080518082019091526009815268746f707570206c6f7760b81b602082015260648311610f8a5760405162461bcd60e51b81526004016105059190613293565b505b6001600160a01b0384166000908152600c6020526040902080548490829060ff191660018381811115610fbb57fe5b0217905550600180820184905560028201805460ff191690911790556040517fcf085312d79a75faa5f1b9f6bec58a64813338f5e5e5759573cab22c6da2d25b906110079083906133b0565b60405180910390a15061099f565b61099f600036611d1c565b600d5481565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156110c25780601f10611097576101008083540402835291602001916110c2565b820191906000526020600020905b8154815290600101906020018083116110a557829003601f168201915b5050505050905082565b600754600854600954600a54600654600d5494959394929391929091565b600054600160a01b900460ff1615611140576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000100000000000000000000000000000000000000281565b6111cf610595565b6001600160a01b0316336001600160a01b03161461122b576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b61126461125f83836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250611e9f565b611fce565b61126e8282611ff2565b5050565b7f0000000000000000000000000000000000000000000000000000000062d1b8d681565b61129e612ddc565b6112a86004611b65565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b828210156113775760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611306565b50505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081525050905090565b336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614611421576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b600061142d6004612105565b9050600061143961216e565b90506000611447478361218f565b9050801561146057600d5461145c9082611bda565b600d555b7f992ba5c7b7d6602101783b4d28d0b93011fb883039e68c729b933bf711678627838260405161149192919061340e565b60405180910390a1505050476114a561216e565b146040518060400160405280600e81526020016d6f7574206f662062616c616e636560901b815250906114eb5760405162461bcd60e51b81526004016105059190613293565b50565b600b5481565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614611577576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b6002546001600160a01b031681565b6115946117b5565b600054600160a81b900460ff16156115f3576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600981526824b7333630ba34b7b760b91b602082015290565b600b5460009061064a9062015180611bda565b611684612ddc565b61168f6004836121ec565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561175e5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a083015290835290920191016116ed565b5050509082525060018201546020820152600282015460408201526003820154606082015260049091015460809091015290525092915050565b3d604051818101604052816000823e82156117b1578181f35b8181fd5b6117bd6105ba565b6001600160a01b0316336001600160a01b031614611814576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b5490565b600360009054906101000a90046001600160a01b03166001600160a01b0316633c8c461c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561186a57600080fd5b505af115801561187e573d6000803e3d6000fd5b505050506000600360009054906101000a90046001600160a01b03166001600160a01b0316631b73b4cb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156118d257600080fd5b505afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a91906131d0565b9050600260009054906101000a90046001600160a01b03166001600160a01b031663981940296040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561195c57600080fd5b505af192505050801561198c575060408051601f3d908101601f19168201909252611989918101906131d0565b60015b6119d0576119986134c2565b80610d47575060405180606001604052806026815260200161358a6026913960405162461bcd60e51b81526004016105059190613293565b6119dd600484848461225e565b5060006119ea6004611b65565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611ab95760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611a48565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090507f677db469fe5eaf40f0415f5433ebc8ebe9ac089662feca0280495fb4c96da29181602001518260400151848460000151856060015160200151866060015160400151876060015160600151886060015160800151604051611b58989796959493929190613444565b60405180910390a1505050565b600080611b7183611816565b11604051806040016040528060088152602001676e6f20616e6e756d60c01b81525090611bb15760405162461bcd60e51b81526004016105059190613293565b5081600001826001015481548110611bc557fe5b90600052602060002090600802019050919050565b600082820183811015611c34576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600080611c4985611b65565b60028601546003870154919250611c7191611c64848861231e565b600385019291908761233d565b6003860154909250611c839083611bda565b6003860181905560028601541015611c9757fe5b509392505050565b600080611cab84611b65565b9050611cba600382018461258e565b6004850154909250611ccc9083611bda565b6004850181905560038501541015611ce057fe5b5092915050565b600054600160b01b900460ff1615611d1457333014611d0257fe5b6000805460ff60b01b19169055611814565b6118146117b5565b611d246117b5565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6c57600080fd5b505afa158015611d80573d6000803e3d6000fd5b505050506040513d6020811015611d9657600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b03198616815260016020818152604090922084518155848301518051919450611e1a93928501920190612e09565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b83811015611ee3578181015183820152602001611ecb565b50505050905090810190601f168015611f105780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b8651811015611f7857868181518110611f4657fe5b6020026020010151831415611f7057858181518110611f6157fe5b60200260200101519150611f78565b600101611f31565b506001600160a01b038116611fc3576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b9150505b9392505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600061201d838360405180604001604052806006815260200165537570706c7960d01b815250611e9f565b6003546040519192507f9a9b245c8db671c90d6db95f7ff0c18c15378a1d55ee4aea21759be8ad27d30e9161205d916001600160a01b0316908490613279565b60405180910390a1600380546001600160a01b0319166001600160a01b03831617905560408051808201909152601381527224b7333630ba34b7b720b63637b1b0ba34b7b760691b60208201526120b79084908490611e9f565b600280546001600160a01b0319166001600160a01b0392831617908190556040517f53cd61e1fdebbc2af2597f77a6a3681c1abbd8771874cc85cf65e035cf85b2af92611b58921690613241565b60008061211183611b65565b905061211f816003016126b2565b60058401549092506121319083611bda565b600584018190556004840154101561214557fe5b60068301546121549083611bda565b600684018190556005840154101561216857fe5b50919050565b600d54600a5460095460009261064a9290916121899161218f565b90611bda565b6000828211156121e6576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006121f783611816565b8210604051806040016040528060088152602001676e6f20616e6e756d60c01b815250906122385760405162461bcd60e51b81526004016105059190613293565b5082600001828154811061224857fe5b9060005260206000209060080201905092915050565b600061226985611816565b11156122c05761227884611b65565b60020154831160405180604001604052806009815260200168746f6f206561726c7960b81b815250906122be5760405162461bcd60e51b81526004016105059190613293565b505b83546001810185556000858152602090206008909102016122e38185858561285c565b805460028601546122f391611bda565b60028601558454600110156123175760018581015461231191611bda565b60018601555b5050505050565b6000826002015482111561232e57fe5b611c3460016121898585612886565b600081516000141561235157506000612585565b600061236784612361888861218f565b906128b2565b600188015490925082915061237c9082611bda565b600188015561271060005b84518110156125815760006123be8683815181106123a157fe5b60200260200101516020015184866129199092919063ffffffff16565b90506123ca848261218f565b93506123f68683815181106123db57fe5b6020026020010151602001518461218f90919063ffffffff16565b925060008061241c8c89868151811061240b57fe5b602002602001015160000151612a19565b9150915081156124605760008c600001828154811061243757fe5b9060005260206000209060060201905061245a8482612a7c90919063ffffffff16565b506124b1565b8b54600181018d5560008d8152602090208951600690920201906124a5908a908790811061248a57fe5b60200260200101516000015182612a9890919063ffffffff16565b6124af8185612a7c565b505b8784815181106124bd57fe5b6020026020010151600001516001600160a01b031663e2739563846040518263ffffffff1660e01b81526004016124f491906133e4565b600060405180830381600087803b15801561250e57600080fd5b505af1158015612522573d6000803e3d6000fd5b505050507fea9b87b57d7b678dd3c9da933ff547ad63395e04ee46cd57894c7b53618dc39a88858151811061255357fe5b6020026020010151600001518460405161256e929190613260565b60405180910390a1505050600101612387565b5050505b95945050505050565b6000805b835481101561268e576000836001600160a01b0316634b13e8728660000184815481106125bb57fe5b60009182526020909120600690910201546040516001600160e01b031960e084901b1681526125f6916001600160a01b031690600401613241565b606060405180830381600087803b15801561261057600080fd5b505af1158015612624573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126489190613152565b905061268361267c8287600001858154811061266057fe5b9060005260206000209060060201612ad990919063ffffffff16565b8490611bda565b925050600101612592565b50600283015461269e9082611bda565b6002840181905560018401541015611c3757fe5b6000805b82548110156121685760006126e68460000183815481106126d357fe5b9060005260206000209060060201612c2d565b9050612717818560000184815481106126fb57fe5b9060005260206000209060060201612c4a90919063ffffffff16565b60038401546127269082611bda565b6003850155835484908390811061273957fe5b60009182526020822060069091020154604080516306201f1d60e01b815290516001600160a01b03909216926306201f1d928592600480820193929182900301818588803b15801561278a57600080fd5b505af115801561279e573d6000803e3d6000fd5b50505050506127d2818560000184815481106127b657fe5b9060005260206000209060060201612c6590919063ffffffff16565b60048401546127e19082611bda565b60048501556127f08382611bda565b92507f4839bc860ac633cfbce1fe18dc3c135733eca7b2dc8ed40e6e6b713a431bcf4484600001838154811061282257fe5b600091825260209091206006909102015460405161284b916001600160a01b0316908490613260565b60405180910390a1506001016126b6565b6001840183905561286d8282612c80565b845561287883612caf565b846002018190555050505050565b6002820154600090808311156128a0576000915050611c37565b6128aa8382612cc7565b915050611c37565b6000808211612908576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161291157fe5b049392505050565b6000808211612962576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b8361296f57506000611fc7565b8383028385828161297c57fe5b0414156129955782818161298c57fe5b04915050611fc7565b60008386816129a057fe5b04905060008487816129ae57fe5b06905060008587816129bc57fe5b04905060008688816129ca57fe5b069050612a0c6129de886123618685612ce2565b6121896129eb8686612ce2565b6121896129f88987612ce2565b6121898d612a068c8b612ce2565b90612ce2565b9998505050505050505050565b600080805b8454811015612a7457836001600160a01b0316856000018281548110612a4057fe5b60009182526020909120600690910201546001600160a01b03161415612a6c5780915060019250612a74565b600101612a1e565b509250929050565b6001820154612a8b9082611bda565b6001830155600290910155565b81546001600160a01b0319166001600160a01b0391909116178155600060018201819055600282018190556003820181905560048201819055600590910155565b81546000906001600160a01b0316318183516001811115612af657fe5b1415612b975760208301516002850154600091612b1591906064612919565b9050600082821115612b2e57612b2b828461218f565b90505b6000612b3987612c2d565b905081811115612b4c5760009450612b59565b612b56828261218f565b94505b6000612b808860040154612b7a848b6001015461218f90919063ffffffff16565b9061218f565b905080861115612b8e578095505b50505050612bcc565b600183516001811115612ba657fe5b1415612bc65760038401546001850154612bbf9161218f565b9150612bcc565b60009150fe5b6003840154612bdb9083611bda565b600385015583546040517f9145b1e2df1630c4e7b11419b36afb9de07a4dc780726dfa970f265b1d627ad791612c1e916001600160a01b03909116908590613260565b60405180910390a15092915050565b6000611c378260040154836003015461218f90919063ffffffff16565b6004820154612c599082611bda565b82600401819055505050565b6005820154612c749082611bda565b82600501819055505050565b6000611c34612c9384846201d4c0612919565b612caa6b1027e72f1f12813088000000600c6128b2565b612d3b565b6000611c376001612cc184601e612d51565b90612d66565b600081831115612cd657600080fd5b62015180838303612911565b600082612cf157506000611c37565b82820282848281612cfe57fe5b0414611c345760405162461bcd60e51b81526004018080602001828103825260218152602001806135b06021913960400191505060405180910390fd5b6000818310612d4a5781611c34565b5090919050565b620151808102820182811015611c3757600080fd5b80820382811115611c3757600080fd5b6040805160608101909152806000815260006020820181905260409091015290565b50805460018160011615610100020316600290046000825580601f10612dbe57506114eb565b601f0160209004906000526020600020908101906114eb9190612e8d565b6040518060800160405280600081526020016000815260200160008152602001612e04612ea2565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612e3f5760008555612e85565b82601f10612e5857805160ff1916838001178555612e85565b82800160010185558215612e85579182015b82811115612e85578251825591602001919060010190612e6a565b50610eb59291505b5b80821115610eb55760008155600101612e8e565b6040518060a0016040528060608152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612ee1578081fd5b81356020612ef6612ef18361349e565b61347a565b8281528181019085830183850287018401881015612f12578586fd5b855b85811015612f39578135612f2781613567565b84529284019290840190600101612f14565b5090979650505050505050565b600060208284031215612f57578081fd5b8135611c3481613567565b60008060408385031215612f74578081fd5b823567ffffffffffffffff80821115612f8b578283fd5b818501915085601f830112612f9e578283fd5b81356020612fae612ef18361349e565b82815281810190858301838502870184018b1015612fca578788fd5b8796505b84871015612fec578035835260019690960195918301918301612fce565b5096505086013592505080821115613002578283fd5b5061300f85828601612ed1565b9150509250929050565b6000602080838503121561302b578182fd5b825167ffffffffffffffff80821115613042578384fd5b818501915085601f830112613055578384fd5b8151613063612ef18261349e565b818152848101908486016040808502870188018b1015613081578889fd5b8896505b848710156130db5780828c03121561309b578889fd5b805181810181811088821117156130ae57fe5b825282516130bb81613567565b815282890151898201528452600196909601959287019290810190613085565b50909998505050505050505050565b6000602082840312156130fb578081fd5b81356001600160e01b031981168114611c34578182fd5b600080600060608486031215613126578081fd5b833561313181613567565b925060208401356131418161357c565b929592945050506040919091013590565b600060608284031215613163578081fd5b6040516060810181811067ffffffffffffffff8211171561318057fe5b604052825161318e8161357c565b815260208381015190820152604083015180151581146131ac578283fd5b60408201529392505050565b6000602082840312156131c9578081fd5b5035919050565b6000602082840312156131e1578081fd5b5051919050565b60008151808452815b8181101561320d576020818501810151868301820152016131f1565b8181111561321e5782602083870101525b50601f01601f19169290920160200192915050565b6002811061323d57fe5b9052565b6001600160a01b0391909116815260200190565b901515815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b600060208252611c3460208301846131e8565b6000602080835260a0845182850152818501516040818187015280870151915060608281880152808801519250608080818901526101408801845186878b01528181518084526101608c01915089830193508a92505b8083101561335057835180516001600160a01b031683528a8101518b84015287810151888401528681015187840152858101518684015289015189830152928901926001929092019160c0909101906132fc565b509786015160c08b015250509183015160e08801528201516101008701520151610120909401939093529392505050565b6000606082019050613394828451613233565b6020830151602083015260408301511515604083015292915050565b60006060820190506133c68260ff855416613233565b6001830154602083015260029092015460ff16151560409091015290565b90815260200190565b60008382526040602083015261340660408301846131e8565b949350505050565b918252602082015260400190565b958652602086019490945260408501929092526060840152608083015260a082015260c00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405181810167ffffffffffffffff8111828210171561349657fe5b604052919050565b600067ffffffffffffffff8211156134b257fe5b5060209081020190565b60e01c90565b600060443d10156134d25761064d565b600481823e6308c379a06134e682516134bc565b146134f05761064d565b6040513d600319016004823e80513d67ffffffffffffffff8160248401118184111715613520575050505061064d565b8284019250825191508082111561353a575050505061064d565b503d830160208284010111156135525750505061064d565b601f01601f1916810160200160405291505090565b6001600160a01b03811681146114eb57600080fd5b600281106114eb57600080fdfe756e6b6e6f776e206572726f722e20676574416e6e75616c50657263656e7461676542697073536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77756e6b6e6f776e206572726f722e20757064617465417574686f72697a6564496e666c6174696f6e416e6443697263756c6174696e67537570706c79a2646970667358221220af53d0910e3dbc2ae5a50387c42e79d3b6aaabbc6b4641120525a0dfad5d8f4f64736f6c63430007060033