Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- IncentivePool
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- Verified at
- 2022-07-13T21:16:23.474570Z
Constructor Arguments
0000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b00000000000000000000000010000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000063718500
Arg [0] (address) : 0x4598a6c05910ab914f0cbaaca1911cd337d10d29
Arg [1] (address) : 0x1000000000000000000000000000000000000002
Arg [2] (address) : 0xbaf89d873d198ff78e72d2745b01cba3c6e5be6b
Arg [3] (address) : 0x1000000000000000000000000000000000000005
Arg [4] (uint256) : 1668384000
./contracts/tokenPools/implementation/IncentivePool.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../../genesis/implementation/FlareDaemon.sol"; import "../../genesis/interface/IFlareDaemonize.sol"; import "../../utils/implementation/GovernedAndFlareDaemonized.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../lib/IncentivePoolAnnum.sol"; import "../lib/IncentivePoolAnnums.sol"; import "../interface/IIIncentivePoolAllocation.sol"; import "../lib/IncentivePoolRewardService.sol"; import "../../inflation/interface/IISupply.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; import "../interface/IITokenPool.sol"; import "../../genesis/implementation/IncentivePoolTreasury.sol"; /** * @title IncentivePool * @notice A contract to manage the process of recognizing, authorizing and funding * native tokens for Flare services that are rewardable by incentivePool. **/ contract IncentivePool is GovernedAndFlareDaemonized, IFlareDaemonize, IITokenPool, AddressUpdatable { using IncentivePoolAnnums for IncentivePoolAnnums.IncentivePoolAnnumsState; using SafeMath for uint256; using SafePct for uint256; // Composable contracts IncentivePoolTreasury public immutable treasury; IIIncentivePoolAllocation public incentivePoolAllocation; IISupply public supply; // The annums IncentivePoolAnnums.IncentivePoolAnnumsState private incentivePoolAnnums; // IncentivePool annum data // Instance vars uint256 public lastAuthorizationTs; // The last time incentive was authorized mapping(IIIncentivePoolReceiver => TopupConfiguration) internal topupConfigurations; // A topup configuration for a contract // receiving incentive. uint256 public immutable rewardEpochStartTs; // Do not start incentivePool 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_TOPUP_HIGH = "topup high"; string internal constant ERR_GET_ANNUAL_PERCENT = "unknown error. getAnnualPercentageBips"; string internal constant ERR_TREASURY_ONLY = "treasury only"; uint256 internal constant BIPS100 = 1e4; // 100% in basis points uint256 internal constant DEFAULT_TOPUP_FACTOR_X100 = 120; uint256 internal constant MAX_DAILY_TOPUP_FACTOR_X100 = 400; uint256 internal constant AUTHORIZE_TIME_FRAME_SEC = 1 days; event IncentiveAuthorized(uint256 amountWei); event TopupRequested(uint256 amountWei); event IncentivePoolAllocationSet(IIIncentivePoolAllocation incentivePoolAllocation); event IncentivePoolRewardServiceTopupComputed(IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei); event IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed( IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei); event IncentivePoolRewardServiceTopupRequestReceived( IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei); event SupplySet(IISupply oldSupply, IISupply newSupply); event TopupConfigurationSet(TopupConfiguration topupConfiguration); event NewAnnumInitialized( uint256 startTimeStamp, uint256 endTimeStamp, uint256 inflatableSupplyWei, uint256 recognizedIncentiveWei, uint256 totalAuthorizedIncentiveWei, uint256 totalIncentiveTopupRequestedWei, uint256 totalIncentiveTopupReceivedWei, uint256 totalIncentiveTopupWithdrawnWei ); modifier notZero(address _address) { require(_address != address(0), ERR_IS_ZERO); _; } constructor ( address _governance, FlareDaemon _flareDaemon, address _addressUpdater, IncentivePoolTreasury _treasury, uint256 _rewardEpochStartTs ) notZero(address(_treasury)) GovernedAndFlareDaemonized(_governance, _flareDaemon) AddressUpdatable(_addressUpdater) { treasury = _treasury; rewardEpochStartTs = _rewardEpochStartTs; } /** * @notice Needed in order to receive funds from Treasury */ receive() external payable { require(msg.sender == address(treasury), ERR_TREASURY_ONLY); } /** * @notice Return token pool supply data * @return _lockedFundsWei Funds that are intentionally locked in the token pool * and not part of circulating supply * @return _totalInflationAuthorizedWei Total inflation authorized amount (wei) * @return _totalClaimedWei Total claimed amount (wei) */ function getTokenPoolSupplyData() external view override returns ( uint256 _lockedFundsWei, uint256 _totalInflationAuthorizedWei, uint256 _totalClaimedWei ){ _lockedFundsWei = address(treasury).balance.add(incentivePoolAnnums.totalIncentiveTopupWithdrawnWei); _totalInflationAuthorizedWei = 0; _totalClaimedWei = incentivePoolAnnums.totalIncentiveTopupWithdrawnWei; } /** * @notice Get a tuple of totals across incentivePool annums. * @return _totalAuthorizedIncentiveWei Total authorized incentive * @return _totalIncentiveTopupRequestedWei Total incentive requested to be topped up for rewarding * @return _totalIncentiveTopupReceivedWei Total incentive received for funding reward services * @return _totalIncentiveTopupWithdrawnWei Total incentive used for funding reward services * @return _totalRecognizedIncentiveWei Total incentive recognized for rewarding */ function getTotals() external view returns ( uint256 _totalAuthorizedIncentiveWei, uint256 _totalIncentiveTopupRequestedWei, uint256 _totalIncentiveTopupReceivedWei, uint256 _totalIncentiveTopupWithdrawnWei, uint256 _totalRecognizedIncentiveWei ) { _totalAuthorizedIncentiveWei = incentivePoolAnnums.totalAuthorizedIncentiveWei; _totalIncentiveTopupRequestedWei = incentivePoolAnnums.totalIncentiveTopupRequestedWei; _totalIncentiveTopupReceivedWei = incentivePoolAnnums.totalIncentiveTopupReceivedWei; _totalIncentiveTopupWithdrawnWei = incentivePoolAnnums.totalIncentiveTopupWithdrawnWei; _totalRecognizedIncentiveWei = incentivePoolAnnums.totalRecognizedIncentiveWei; } /** * @notice Given an index, return the annum at that index. * @param _index The index of the annum to fetch. * @return The incentivePool annum state. * @dev Expect library to revert if index not found. */ function getAnnum(uint256 _index) external view returns(IncentivePoolAnnum.IncentivePoolAnnumState memory) { return incentivePoolAnnums.getAnnum(_index); } /** * @notice Return the current annum. * @return The incentivePool annum state of the current annum. * @dev Expect library to revert if there is no current annum. */ function getCurrentAnnum() external view returns(IncentivePoolAnnum.IncentivePoolAnnumState memory) { return incentivePoolAnnums.getCurrentAnnum(); } /** * @notice Set the topup configuration for a reward service. * @param _incentivePoolReceiver The reward service to receive the incentivePool 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 incentive 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 > 100 and <= 400. */ function setTopupConfiguration( IIIncentivePoolReceiver _incentivePoolReceiver, TopupType _topupType, uint256 _topupFactorX100 ) external notZero(address(_incentivePoolReceiver)) onlyGovernance { if (_topupType == TopupType.FACTOROFDAILYAUTHORIZED) { require(_topupFactorX100 > 100, ERR_TOPUP_LOW); require(_topupFactorX100 <= MAX_DAILY_TOPUP_FACTOR_X100, ERR_TOPUP_HIGH); } TopupConfiguration storage topupConfiguration = topupConfigurations[_incentivePoolReceiver]; topupConfiguration.topupType = _topupType; topupConfiguration.topupFactorX100 = _topupFactorX100; topupConfiguration.configured = true; emit TopupConfigurationSet(topupConfiguration); } /** * @notice Given an incentivePool receiver, get the topup configuration. * @param _incentivePoolReceiver The reward service. * @return _topupConfiguration The configurartion of how the topup requests are calculated for a given * reward service. */ function getTopupConfiguration( IIIncentivePoolReceiver _incentivePoolReceiver ) external notZero(address(_incentivePoolReceiver)) returns(TopupConfiguration memory _topupConfiguration) { TopupConfiguration storage topupConfiguration = topupConfigurations[_incentivePoolReceiver]; 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 incentive process. * @dev There are two events: * 1) an annual event to recognize incentive for a new annum * 2) a daily event to: * a) authorize incentive for rewarding * b) distribute enough native tokens to topup reward services for claiming reserves */ function daemonize() external virtual override notZero(address(supply)) onlyFlareDaemon returns(bool) { // If incentive rewarding not started yet, blow off processing until it does. if (rewardEpochStartTs == 0 || block.timestamp < rewardEpochStartTs) { return true; } // If incetive 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 incentivePool annum? if (incentivePoolAnnums.getCount() == 0) { _initNewAnnum(block.timestamp); } else { uint256 currentAnnumEndTimeStamp = incentivePoolAnnums.getCurrentAnnum().endTimeStamp; // Is it time to recognize a new incentivePool annum? if (block.timestamp > currentAnnumEndTimeStamp) { _initNewAnnum(currentAnnumEndTimeStamp.add(1)); } } // Is it time to authorize new incentive? Do it daily. if (lastAuthorizationTs.add(AUTHORIZE_TIME_FRAME_SEC) <= block.timestamp) { // Update time we last authorized. lastAuthorizationTs = block.timestamp; // Authorize incentive for current sharing percentages. uint256 amountAuthorizedWei = incentivePoolAnnums.authorizeDailyIncentive( block.timestamp, treasury.MAX_DAILY_PULL_AMOUNT_WEI().mulDiv(100, MAX_DAILY_TOPUP_FACTOR_X100), incentivePoolAllocation.getSharingPercentages() ); emit IncentiveAuthorized(amountAuthorizedWei); // Time to compute topup amount for incentivePool receivers. uint256 topupRequestWei = incentivePoolAnnums.computeTopupRequest(this); emit TopupRequested(topupRequestWei); // Pull funds from treasury contract treasury.pullFunds(topupRequestWei); // Distribute received funds uint256 amountPostedWei = incentivePoolAnnums.distributeTopupRequest(); // calculated and distributed amount should be the same assert(topupRequestWei == amountPostedWei); } return true; } function switchToFallbackMode() external view override onlyFlareDaemon returns (bool) { // do nothing - there is no fallback mode in IncentivePool return false; } /** * @notice Implement this function for updating daemonized contracts through AddressUpdater. */ function getContractName() external pure override returns (string memory) { return "IncentivePool"; } /** * @notice Returns next expected incentive topup timestamp which is also incentive 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 same block. */ function getNextExpectedTopupTs() external view returns (uint256 _nextTopupTs) { _nextTopupTs = lastAuthorizationTs.add(AUTHORIZE_TIME_FRAME_SEC); } /** * @notice Implementation of the AddressUpdatable abstract method - updates supply and incentivePool allocation. * @notice Set a reference to a provider of sharing percentages by incentivePool receiver. * @dev Assume that sharing percentages sum to 100% if at least one exists, but * if no sharing percentages are defined, then no incentive will be authorized. * @notice Set a reference to a provider of the annual incentivePool 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; incentivePoolAllocation = IIIncentivePoolAllocation( _getContractAddress(_contractNameHashes, _contractAddresses, "IncentivePoolAllocation")); emit IncentivePoolAllocationSet(incentivePoolAllocation); } function _initNewAnnum(uint256 startTs) internal { uint256 inflatableSupply = supply.getInflatableBalance(); uint256 freeTreasuryBalance = address(treasury).balance .add(incentivePoolAnnums.totalIncentiveTopupWithdrawnWei) .sub(incentivePoolAnnums.totalAuthorizedIncentiveWei); try incentivePoolAllocation.getAnnualPercentageBips() returns(uint256 annualPercentBips) { incentivePoolAnnums.initializeNewAnnum(startTs, freeTreasuryBalance, inflatableSupply, annualPercentBips); } catch Error(string memory message) { revert(message); } catch { revert(ERR_GET_ANNUAL_PERCENT); } IncentivePoolAnnum.IncentivePoolAnnumState memory incentivePoolAnnum = incentivePoolAnnums.getCurrentAnnum(); emit NewAnnumInitialized( incentivePoolAnnum.startTimeStamp, incentivePoolAnnum.endTimeStamp, inflatableSupply, incentivePoolAnnum.recognizedIncentiveWei, incentivePoolAnnum.incentivePoolRewardServices.totalAuthorizedIncentiveWei, incentivePoolAnnum.incentivePoolRewardServices.totalIncentiveTopupRequestedWei, incentivePoolAnnum.incentivePoolRewardServices.totalIncentiveTopupReceivedWei, incentivePoolAnnum.incentivePoolRewardServices.totalIncentiveTopupWithdrawnWei ); } }
./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/genesis/implementation/IncentivePoolTreasury.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../../governance/implementation/GovernedAtGenesis.sol"; /** * @title Incentive pool treasury * @notice A genesis contract which holds the entire treasury for the incentive pool. * It enables limited flow of funds to the incentive pool. */ contract IncentivePoolTreasury is GovernedAtGenesis { // How often can incentive pool pull funds - 23 hours constant uint256 internal constant MAX_PULL_FREQUENCY_SEC = 23 hours; uint256 public constant MAX_DAILY_PULL_AMOUNT_WEI = 25000000 ether; // Errors string internal constant ERR_INCENTIVE_POOL_ONLY = "incentive pool only"; string internal constant ERR_TOO_OFTEN = "too often"; string internal constant ERR_TOO_MUCH = "too much"; string internal constant ERR_PULL_FAILED = "pull failed"; string internal constant ERR_ALREADY_SET = "already set"; // Storage address public incentivePool; uint256 public lastPullTs; modifier onlyIncentivePool { require (msg.sender == incentivePool, ERR_INCENTIVE_POOL_ONLY); _; } /** * @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)) { /* empty block */ } /** * @notice Sets incentive pool contract address. * @param _incentivePool Incentive pool contract address. */ function setIncentivePoolContract(address _incentivePool) external onlyGovernance { require(incentivePool == address(0), ERR_ALREADY_SET); incentivePool = _incentivePool; } /** * @notice Moves funds to the incentive pool contract (once per day) * @param _amountWei The amount of wei to pull to incentive pool contract */ function pullFunds(uint256 _amountWei) external onlyIncentivePool { // this also serves as reentrancy guard, since any re-entry will happen in the same block require(lastPullTs + MAX_PULL_FREQUENCY_SEC <= block.timestamp, ERR_TOO_OFTEN); require(_amountWei <= MAX_DAILY_PULL_AMOUNT_WEI, ERR_TOO_MUCH); lastPullTs = block.timestamp; /* solhint-disable avoid-low-level-calls */ //slither-disable-next-line arbitrary-send (bool success, ) = msg.sender.call{value: _amountWei}(""); /* solhint-enable avoid-low-level-calls */ require(success, ERR_PULL_FAILED); } }
./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/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/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/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/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/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/tokenPools/interface/IIIncentivePoolAllocation.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; import "./IIIncentivePoolPercentageProvider.sol"; import "./IIIncentivePoolSharingPercentageProvider.sol"; interface IIIncentivePoolAllocation is IIIncentivePoolPercentageProvider, IIIncentivePoolSharingPercentageProvider { }
./contracts/tokenPools/interface/IIIncentivePoolPercentageProvider.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIIncentivePoolPercentageProvider { /** * Return the annual incentivePool rate in bips. */ function getAnnualPercentageBips() external returns(uint256); }
./contracts/tokenPools/interface/IIIncentivePoolReceiver.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIIncentivePoolReceiver { /** * Notify the receiver that it is entitled to receive `_toAuthorizeWei` incentive amount. * @param _toAuthorizeWei the amount of incentive that can be awarded in the coming day */ function setDailyAuthorizedIncentive(uint256 _toAuthorizeWei) external; /** * Receive native tokens from incentivePool. */ function receiveIncentive() external payable; /** * IncentivePool receivers have a reference to the IncentivePool contract. */ function getIncentivePoolAddress() external returns(address); /** * Implement this function for updating incentivePool receiver contracts through AddressUpdater. */ function getContractName() external view returns (string memory); }
./contracts/tokenPools/interface/IIIncentivePoolSharingPercentageProvider.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; import "./IIIncentivePoolReceiver.sol"; struct SharingPercentage { IIIncentivePoolReceiver incentivePoolReceiver; uint256 percentBips; } interface IIIncentivePoolSharingPercentageProvider { /** * Return the shared percentage per incentivPool 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); }
./contracts/tokenPools/interface/IITokenPool.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IITokenPool { /** * @notice Return token pool supply data * @return _lockedFundsWei Funds that are intentionally locked in the token pool * and not part of circulating supply * @return _totalInflationAuthorizedWei Total inflation authorized amount (wei) * @return _totalClaimedWei Total claimed amount (wei) */ function getTokenPoolSupplyData() external returns ( uint256 _lockedFundsWei, uint256 _totalInflationAuthorizedWei, uint256 _totalClaimedWei ); }
./contracts/tokenPools/lib/IncentivePoolAnnum.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../../utils/implementation/DateTimeLibrary.sol"; import "./IncentivePoolRewardServices.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 IncentivePool Annum library * @notice A library to manage an incentivePool annum. **/ library IncentivePoolAnnum { using BokkyPooBahsDateTimeLibrary for uint256; using IncentivePoolAnnum for IncentivePoolAnnum.IncentivePoolAnnumState; using SafeCast for uint256; using SafeMath for uint256; using SafePct for uint256; /** * @dev `IncentivePoolAnnumState` is state structure used by this library to manage * an incentivePool annum. */ struct IncentivePoolAnnumState { uint256 recognizedIncentiveWei; uint256 startTimeStamp; uint256 endTimeStamp; IncentivePoolRewardServices.IncentivePoolRewardServicesState incentivePoolRewardServices; } uint256 internal constant BIPS100 = 1e4; // 100% in basis points uint256 internal constant MAX_ANNUAL_FACTOR_BIPS = 1e3; // 10% in basis points /** * @notice Helper function to compute recognized incentive. * @param _treasuryBalance The treasury balance used to recognize incentive. * @param _inflatableBalance The inflatable balance used to recognize incentive. * @param _annualIncentivePoolPercentageBips The annual percentage used to recognize incentive. * @return The computed recognized incentive. */ function _computeRecognizedIncentiveWei( uint256 _treasuryBalance, uint256 _inflatableBalance, uint256 _annualIncentivePoolPercentageBips ) internal pure returns(uint256) { return Math.min( _inflatableBalance.mulDiv(_annualIncentivePoolPercentageBips, 12 * BIPS100), _treasuryBalance.mulDiv(MAX_ANNUAL_FACTOR_BIPS, 12 * BIPS100) ); // monthly incentive } /** * @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( IncentivePoolAnnumState 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( IncentivePoolAnnumState 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 _treasuryBalance The treasury balance used to calculate recognized * incentive for the new annum. * @param _inflatableBalanceWei The inflatable balance used to calculate recognized * incentive for the new annum. * @param _annualIncentivePoolPercentageBips The annual incentivePool percentage in bips to calc recognized * incentivePool. * @dev A newly created IncentivePoolAnnumState is expected to exist. */ function initialize( IncentivePoolAnnumState storage _self, uint256 _startTimeStamp, uint256 _treasuryBalance, uint256 _inflatableBalanceWei, uint256 _annualIncentivePoolPercentageBips ) internal { _self.startTimeStamp = _startTimeStamp; _self.recognizedIncentiveWei = _computeRecognizedIncentiveWei( _treasuryBalance, _inflatableBalanceWei, _annualIncentivePoolPercentageBips); _self.endTimeStamp = _getAnnumEndsTs(_startTimeStamp); } }
./contracts/tokenPools/lib/IncentivePoolAnnums.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../implementation/IncentivePool.sol"; import "./IncentivePoolAnnum.sol"; import "./IncentivePoolRewardServices.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; import "../interface/IIIncentivePoolSharingPercentageProvider.sol"; /** * @title IncentivePool Annums library * @notice A library to manage a collection of incentivePool annum and associated totals. * @dev Operations such as authorizing daily incentive 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 IncentivePoolAnnums { using IncentivePoolAnnum for IncentivePoolAnnum.IncentivePoolAnnumState; using IncentivePoolRewardServices for IncentivePoolRewardServices.IncentivePoolRewardServicesState; using SafeMath for uint256; using SafePct for uint256; /** * @dev `IncentivePoolAnnumsState` is state structure used by this library to manage * a collection of incentivePool annums and associated totals. */ struct IncentivePoolAnnumsState { // Collection of annums IncentivePoolAnnum.IncentivePoolAnnumState[] incentivePoolAnnums; uint256 currentAnnum; // Balances uint256 totalRecognizedIncentiveWei; uint256 totalAuthorizedIncentiveWei; uint256 totalIncentiveTopupRequestedWei; uint256 totalIncentiveTopupReceivedWei; uint256 totalIncentiveTopupWithdrawnWei; } string internal constant ERR_NO_ANNUM = "no annum"; string internal constant ERR_TOO_EARLY = "too early"; /** * @notice Dispatch incentivePool authorization to be performed across all reward services according to their * sharing percentage for the current annum, and then maintain sum total of incentive * authorized across all annums. * @param _atTimeStamp The timestamp at which the number of daily periods remaining in the current * annum will be calculated. * @param _maxAuthorizeAmountWei The maximum amount that can be authorized according to treasury pull limits. * @param _sharingPercentages An array of the sharing percentages by incentivePool receiver used to * allocate authorized incentive. * @return _amountAuthorizedWei The amount of incentive authorized for this authorization cycle. * @dev Invariant: total incentive authorized cannot be greater than total incentive recognized. */ function authorizeDailyIncentive( IncentivePoolAnnumsState storage _self, uint256 _atTimeStamp, uint256 _maxAuthorizeAmountWei, SharingPercentage[] memory _sharingPercentages ) internal returns(uint256 _amountAuthorizedWei) { // Get the current annum IncentivePoolAnnum.IncentivePoolAnnumState storage currentAnnum = getCurrentAnnum(_self); // Authorize daily incentive for the current annum, across reward services, given // sharing percentages. _amountAuthorizedWei = currentAnnum.incentivePoolRewardServices.authorizeDailyIncentive( _self.totalRecognizedIncentiveWei, _self.totalAuthorizedIncentiveWei, currentAnnum.getPeriodsRemaining(_atTimeStamp), _maxAuthorizeAmountWei, _sharingPercentages); // Accumulate total authorized incentive across all annums _self.totalAuthorizedIncentiveWei = _self.totalAuthorizedIncentiveWei.add(_amountAuthorizedWei); // Make sure that total authorized never exceeds total recognized assert(_self.totalAuthorizedIncentiveWei <= _self.totalRecognizedIncentiveWei); } /** * @notice Dispatch topup request calculations across reward services and sum up total mint request made * to fund topup of reward services. * @param _incentivePool The IncentivePool contract containing the topup confguration of each reward service. * @return _topupRequestWei The amount of native token requested across reward services for this cycle. * @dev Invariant: total incentive topup requested cannot exceed total incentive authorized */ function computeTopupRequest( IncentivePoolAnnumsState storage _self, IncentivePool _incentivePool ) internal returns(uint256 _topupRequestWei) { // Get the current annum IncentivePoolAnnum.IncentivePoolAnnumState storage currentAnnum = getCurrentAnnum(_self); // Compute the topup _topupRequestWei = currentAnnum.incentivePoolRewardServices.computeTopupRequest(_incentivePool); // Sum the topup request total across annums _self.totalIncentiveTopupRequestedWei = _self.totalIncentiveTopupRequestedWei.add(_topupRequestWei); // Make sure that total topup requested can never exceed incentive authorized assert(_self.totalIncentiveTopupRequestedWei <= _self.totalAuthorizedIncentiveWei); } /** * @notice Distribute native tokens 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 distributeTopupRequest( IncentivePoolAnnumsState storage _self ) internal returns(uint256 _amountPostedWei) { // Get the current annum IncentivePoolAnnum.IncentivePoolAnnumState storage currentAnnum = getCurrentAnnum(_self); // Distribute topup request. Post to received and withdrawn buckets for each reward service. _amountPostedWei = currentAnnum.incentivePoolRewardServices.distributeTopupRequest(); // Post the amount of native tokens received into the IncentivePool contract _self.totalIncentiveTopupReceivedWei = _self.totalIncentiveTopupReceivedWei.add(_amountPostedWei); // Received should never be more than requested assert(_self.totalIncentiveTopupReceivedWei <= _self.totalIncentiveTopupRequestedWei); // Post amount withdrawn and transferred to reward service contracts _self.totalIncentiveTopupWithdrawnWei = _self.totalIncentiveTopupWithdrawnWei.add(_amountPostedWei); // Withdrawn should never be more than received assert(_self.totalIncentiveTopupWithdrawnWei <= _self.totalIncentiveTopupReceivedWei); } /** * @notice Get the number of incentivePool annums. * @return The count. */ function getCount(IncentivePoolAnnumsState storage _self) internal view returns(uint256) { return _self.incentivePoolAnnums.length; } /** * @notice Given an index, return a given incentivePool annum data. * @param _index The index of the annum to fetch. * @return _incentivePoolAnnum Returns IncentivePoolAnnum.IncentivePoolAnnumState found at _index. * @dev Will revert if index not found. */ function getAnnum( IncentivePoolAnnumsState storage _self, uint256 _index ) internal view returns (IncentivePoolAnnum.IncentivePoolAnnumState storage _incentivePoolAnnum) { require(_index < getCount(_self), ERR_NO_ANNUM); _incentivePoolAnnum = _self.incentivePoolAnnums[_index]; } /** * @notice Return incentivePool annum data for the current annum. * @return _incentivePoolAnnum Returns IncentivePoolAnnum.IncentivePoolAnnumState for the current annum. * @dev Will revert if no current annum. */ function getCurrentAnnum( IncentivePoolAnnumsState storage _self ) internal view returns (IncentivePoolAnnum.IncentivePoolAnnumState storage _incentivePoolAnnum) { require(getCount(_self) > 0, ERR_NO_ANNUM); _incentivePoolAnnum = _self.incentivePoolAnnums[_self.currentAnnum]; } /** * @notice Initialize a new annum, add it to the annum collection, maintian running total * of recognized incentive resulting from new annum, and set current annum pointer. * @param _startTimeStamp The timestamp to start the annum. * @param _treasuryBalance The treasury balance used to recognize incentive. * @param _inflatableBalance The inflatable balance used to recognize incentive. * @param _annualIncentivePoolPercentageBips The incentivePool percentage in bips to use when recognizing * incentive. */ function initializeNewAnnum( IncentivePoolAnnumsState storage _self, uint256 _startTimeStamp, uint256 _treasuryBalance, uint256 _inflatableBalance, uint256 _annualIncentivePoolPercentageBips ) 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 IncentivePoolAnnum.IncentivePoolAnnumState storage incentivePoolAnnum = _self.incentivePoolAnnums.push(); // Initialize it with newly passed in annum info incentivePoolAnnum.initialize( _startTimeStamp, _treasuryBalance, _inflatableBalance, _annualIncentivePoolPercentageBips ); // Accumulate total recognized incentive across annums _self.totalRecognizedIncentiveWei = _self.totalRecognizedIncentiveWei.add(incentivePoolAnnum.recognizedIncentiveWei); // Reposition index pointing to current annum if (_self.incentivePoolAnnums.length > 1) { _self.currentAnnum = _self.currentAnnum.add(1); } } }
./contracts/tokenPools/lib/IncentivePoolRewardService.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../interface/IIIncentivePoolReceiver.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 incentive 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 incentivePool-related totals. When a topup configuration is applied, a reward service can * also make requests to topup native tokens within a reward contract. * @dev A reward service exists within the context of a given incentivePool annum. **/ library IncentivePoolRewardService { using SafeMath for uint256; using SafePct for uint256; /** * @dev `IncentivePoolRewardServiceState` is state structure used by this library to manage * an a reward service tracking authorize incentivePool. */ struct IncentivePoolRewardServiceState { IIIncentivePoolReceiver incentivePoolReceiver; // The target rewarding contract uint256 authorizedIncentiveWei; // Total authorized incentive for this reward service uint256 lastDailyAuthorizedIncentiveWei; // Last daily authorized incentive amount uint256 incentivePoolTopupRequestedWei; // Total incentive topup requested uint256 incentivePoolTopupReceivedWei; // Total incentive topup received uint256 incentivePoolTopupWithdrawnWei; // Total incentive sent to rewarding service contract } event IncentivePoolRewardServiceTopupComputed(IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei); /** * @notice Maintain authorized incentive total for service. * @param _amountWei Amount to add. */ function addAuthorizedIncentive(IncentivePoolRewardServiceState storage _self, uint256 _amountWei) internal { _self.authorizedIncentiveWei = _self.authorizedIncentiveWei.add(_amountWei); _self.lastDailyAuthorizedIncentiveWei = _amountWei; } /** * @notice Maintain topup native tokens received total for service. * @param _amountWei Amount to add. */ function addTopupReceived(IncentivePoolRewardServiceState storage _self, uint256 _amountWei) internal { _self.incentivePoolTopupReceivedWei = _self.incentivePoolTopupReceivedWei.add(_amountWei); } /** * @notice Maintain topup native tokens withdrawn (funded) total for service. * @param _amountWei Amount to add. */ function addTopupWithdrawn(IncentivePoolRewardServiceState storage _self, uint256 _amountWei) internal { _self.incentivePoolTopupWithdrawnWei = _self.incentivePoolTopupWithdrawnWei.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( IncentivePoolRewardServiceState storage _self, TopupConfiguration memory _topupConfiguration ) internal returns (uint256 _topupRequestWei) { // Get the balance of the incentivePool receiver uint256 incentivePoolReceiverBalanceWei = address(_self.incentivePoolReceiver).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.lastDailyAuthorizedIncentiveWei .mulDiv(_topupConfiguration.topupFactorX100, 100); uint256 rawTopupRequestWei = 0; // If current balance is less then requested, request some more. if (requestedBalanceWei > incentivePoolReceiverBalanceWei) { rawTopupRequestWei = requestedBalanceWei.sub(incentivePoolReceiverBalanceWei); } // 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.authorizedIncentiveWei .sub(topupPendingWei) .sub(_self.incentivePoolTopupReceivedWei); if (_topupRequestWei > maxTopupRequestWei) { _topupRequestWei = maxTopupRequestWei; } } else if (_topupConfiguration.topupType == TopupType.ALLAUTHORIZED) { _topupRequestWei = _self.authorizedIncentiveWei .sub(_self.incentivePoolTopupRequestedWei); } else { // This code is unreachable since TopupType currently has only 2 constructors _topupRequestWei = 0; assert(false); } _self.incentivePoolTopupRequestedWei = _self.incentivePoolTopupRequestedWei.add(_topupRequestWei); emit IncentivePoolRewardServiceTopupComputed(_self.incentivePoolReceiver, _topupRequestWei); } /** * @notice Compute a pending topup request. * @return _pendingTopupWei The amount pending to be sent. */ function getPendingTopup( IncentivePoolRewardServiceState storage _self ) internal view returns(uint256 _pendingTopupWei) { return _self.incentivePoolTopupRequestedWei.sub(_self.incentivePoolTopupReceivedWei); } /** * @notice Initial a new reward service. * @dev Assume service is already instantiated. */ function initialize( IncentivePoolRewardServiceState storage _self, IIIncentivePoolReceiver _incentivePoolReceiver ) internal { _self.incentivePoolReceiver = _incentivePoolReceiver; _self.authorizedIncentiveWei = 0; _self.lastDailyAuthorizedIncentiveWei = 0; _self.incentivePoolTopupRequestedWei = 0; _self.incentivePoolTopupReceivedWei = 0; _self.incentivePoolTopupWithdrawnWei = 0; } }
./contracts/tokenPools/lib/IncentivePoolRewardServices.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../../utils/implementation/DateTimeLibrary.sol"; import "../implementation/IncentivePool.sol"; import "../interface/IIIncentivePoolReceiver.sol"; import "./IncentivePoolRewardService.sol"; import "@openzeppelin/contracts/math/Math.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; import "../interface/IIIncentivePoolSharingPercentageProvider.sol"; import "./IncentivePoolRewardService.sol"; /** * @title Incentive Pool 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 incentivePool * receiver with a sharing percentage used to calculate percentage of authorized incentive 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 sent for claiming reserves, and it stores totals for a given * incentivePool receiver, for a given annum. **/ library IncentivePoolRewardServices { using BokkyPooBahsDateTimeLibrary for uint256; using IncentivePoolRewardService for IncentivePoolRewardService.IncentivePoolRewardServiceState; using SafeMath for uint256; using SafePct for uint256; /** * @dev `IncentivePoolRewardServicesState` is state structure used by this library to manage * a collection of reward services and associated totals. */ struct IncentivePoolRewardServicesState { // Collection of annums IncentivePoolRewardService.IncentivePoolRewardServiceState[] incentivePoolRewardServices; // Balances uint256 totalAuthorizedIncentiveWei; uint256 totalIncentiveTopupRequestedWei; uint256 totalIncentiveTopupReceivedWei; uint256 totalIncentiveTopupWithdrawnWei; } uint256 internal constant BIPS100 = 1e4; // 100% in basis points event IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed( IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei); event IncentivePoolRewardServiceTopupRequestReceived( IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei); /** * @notice For all sharing percentages, compute authorized daily incentive for current cycle * and then allocate it across associated incentivePool receivers according to their sharing percentages, * updating reward service totals along the way. Finally, * set the daily authorized incentive for the given incentivePool receiver. * @param _totalRecognizedIncentiveWei The total recognized incentive across all annums. * @param _totalAuthorizedIncentiveWei The total authorized incentive across all annums. * @param _periodsRemaining The number of periods remaining in the current annum. * @param _maxAuthorizeAmountWei The maximum amount that can be authorized according to treasury pull limits. * @param _sharingPercentages An array of incentive sharing percentages. * @return _amountAuthorizedWei The incentive 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 authorizeDailyIncentive( IncentivePoolRewardServicesState storage _self, uint256 _totalRecognizedIncentiveWei, uint256 _totalAuthorizedIncentiveWei, uint256 _periodsRemaining, uint256 _maxAuthorizeAmountWei, 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 = Math.min( _totalRecognizedIncentiveWei.sub(_totalAuthorizedIncentiveWei).div(_periodsRemaining), _maxAuthorizeAmountWei); // 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.totalAuthorizedIncentiveWei = _self.totalAuthorizedIncentiveWei.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 incentivePoolRewardServiceIndex ) = findIncentivePoolRewardService(_self, _sharingPercentages[i].incentivePoolReceiver); if (found) { // Get the existing reward service IncentivePoolRewardService.IncentivePoolRewardServiceState storage incentivePoolRewardService = _self.incentivePoolRewardServices[incentivePoolRewardServiceIndex]; // Accumulate the amount authorized for the service incentivePoolRewardService.addAuthorizedIncentive(toAuthorizeWei); } else { // Initialize a new reward service IncentivePoolRewardService.IncentivePoolRewardServiceState storage incentivePoolRewardService = _self.incentivePoolRewardServices.push(); incentivePoolRewardService.initialize(_sharingPercentages[i].incentivePoolReceiver); // Accumulate the amount authorized for the service incentivePoolRewardService.addAuthorizedIncentive(toAuthorizeWei); } // Signal the incentivePool receiver of the reward service (the actual rewarding contract) // with amount just authorized. _sharingPercentages[i].incentivePoolReceiver.setDailyAuthorizedIncentive(toAuthorizeWei); emit IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed( _sharingPercentages[i].incentivePoolReceiver, toAuthorizeWei); } } /** * @notice Given topup configurations as maintained by an instantiated IncentivePool contract, compute * the topup requests needed to topup reward contracts with native token reserves to satisfy claim requests. * @param _incentivePool The IncentivePool contract holding the topup configurations. * @return _topupRequestWei The topup request to mint native tokens across reward services for this cycle. */ function computeTopupRequest( IncentivePoolRewardServicesState storage _self, IncentivePool _incentivePool ) internal returns (uint256 _topupRequestWei) { for (uint256 i; i < _self.incentivePoolRewardServices.length; i++) { TopupConfiguration memory topupConfiguration = _incentivePool.getTopupConfiguration(_self.incentivePoolRewardServices[i].incentivePoolReceiver); _topupRequestWei = _topupRequestWei.add(_self.incentivePoolRewardServices[i].computeTopupRequest(topupConfiguration)); } _self.totalIncentiveTopupRequestedWei = _self.totalIncentiveTopupRequestedWei.add(_topupRequestWei); // Make sure topup requested never exceeds the amount authorized assert(_self.totalIncentiveTopupRequestedWei <= _self.totalAuthorizedIncentiveWei); } /** * @notice Given an incentivePool receiver, return the index of the associated reward service. * @param _incentivePoolReceiver The incentivePool receiver. * @return _found True if the reward service was found. * @return _index The index on the incentivePoolRewardServices array of the found service. Index is undefined * if the reward service was not found. */ function findIncentivePoolRewardService( IncentivePoolRewardServicesState storage _self, IIIncentivePoolReceiver _incentivePoolReceiver ) internal view returns(bool _found, uint256 _index) { // The number of these is expected to be low. _found = false; for (uint256 i; i < _self.incentivePoolRewardServices.length; i++) { if (_self.incentivePoolRewardServices[i].incentivePoolReceiver == _incentivePoolReceiver) { _index = i; _found = true; break; } } } /** * @notice Receive a topup request of native tokens and disburse amongst requestors. * @return _amountPostedWei The total amount of native tokens funded. * @dev Assume value is siting in IncentivePool contract waiting to be posted and transmitted. * This function is atomic, so if for some reason not enough native tokens are available, this * function will fail until all topup requests can be satisfied. */ function distributeTopupRequest( IncentivePoolRewardServicesState storage _self ) internal returns(uint256 _amountPostedWei) { // Spin through all reward services for (uint256 i; i < _self.incentivePoolRewardServices.length; i++) { // Get the pending topup for the service uint256 pendingTopupWei = _self.incentivePoolRewardServices[i].getPendingTopup(); // Accumulate topup received _self.incentivePoolRewardServices[i].addTopupReceived(pendingTopupWei); _self.totalIncentiveTopupReceivedWei = _self.totalIncentiveTopupReceivedWei.add(pendingTopupWei); // Transfer topup to rewarding service contract _self.incentivePoolRewardServices[i].incentivePoolReceiver.receiveIncentive{value: pendingTopupWei}(); // Accumulate topup withdrawn _self.incentivePoolRewardServices[i].addTopupWithdrawn(pendingTopupWei); _self.totalIncentiveTopupWithdrawnWei = _self.totalIncentiveTopupWithdrawnWei.add(pendingTopupWei); // Accumulate amount posted _amountPostedWei = _amountPostedWei.add(pendingTopupWei); emit IncentivePoolRewardServiceTopupRequestReceived( _self.incentivePoolRewardServices[i].incentivePoolReceiver, 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/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); } }
@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":"address","name":"_treasury","internalType":"contract IncentivePoolTreasury"},{"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":"IncentiveAuthorized","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolAllocationSet","inputs":[{"type":"address","name":"incentivePoolAllocation","internalType":"contract IIIncentivePoolAllocation","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed","inputs":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolRewardServiceTopupComputed","inputs":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolRewardServiceTopupRequestReceived","inputs":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver","indexed":false},{"type":"uint256","name":"amountWei","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":"recognizedIncentiveWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalAuthorizedIncentiveWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalIncentiveTopupRequestedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalIncentiveTopupReceivedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalIncentiveTopupWithdrawnWei","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 IncentivePoolAnnum.IncentivePoolAnnumState","components":[{"type":"uint256","name":"recognizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardServices.IncentivePoolRewardServicesState","components":[{"type":"tuple[]","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardService.IncentivePoolRewardServiceState[]","components":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"},{"type":"uint256","name":"authorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupWithdrawnWei","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 IncentivePoolAnnum.IncentivePoolAnnumState","components":[{"type":"uint256","name":"recognizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardServices.IncentivePoolRewardServicesState","components":[{"type":"tuple[]","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardService.IncentivePoolRewardServiceState[]","components":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"},{"type":"uint256","name":"authorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupWithdrawnWei","internalType":"uint256"}]}]}],"name":"getCurrentAnnum","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_nextTopupTs","internalType":"uint256"}],"name":"getNextExpectedTopupTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_lockedFundsWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationAuthorizedWei","internalType":"uint256"},{"type":"uint256","name":"_totalClaimedWei","internalType":"uint256"}],"name":"getTokenPoolSupplyData","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":"_incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_totalAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"_totalIncentiveTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"_totalIncentiveTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"_totalIncentiveTopupWithdrawnWei","internalType":"uint256"},{"type":"uint256","name":"_totalRecognizedIncentiveWei","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 IIIncentivePoolAllocation"}],"name":"incentivePoolAllocation","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":"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":"_incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"},{"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":"address","name":"","internalType":"contract IncentivePoolTreasury"}],"name":"treasury","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateContractAddresses","inputs":[{"type":"bytes32[]","name":"_contractNameHashes","internalType":"bytes32[]"},{"type":"address[]","name":"_contractAddresses","internalType":"address[]"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x60e06040523480156200001157600080fd5b506040516200399838038062003998833981016040819052620000349162000273565b82858581806001600160a01b03811615620000545762000054816200018c565b506001600160a01b038116620000a4576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b506001600160a01b038116620000f5576040805162461bcd60e51b8152602060048201526011602482015270666c617265206461656d6f6e207a65726f60781b604482015290519081900360640190fd5b60601b6001600160601b0319166080525062000111816200024f565b5060408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b0382166200016a5760405162461bcd60e51b8152600401620001619190620002e6565b60405180910390fd5b505060609190911b6001600160601b03191660a05260c0525062000355915050565b600054600160a01b900460ff1615620001ec576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600080600080600060a086880312156200028b578081fd5b855162000298816200033c565b6020870151909550620002ab816200033c565b6040870151909450620002be816200033c565b6060870151909350620002d1816200033c565b80925050608086015190509295509295909350565b6000602080835283518082850152825b818110156200031457858101830151858201604001528201620002f6565b81811115620003265783604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146200035257600080fd5b50565b60805160601c60a05160601c60c0516135e3620003b560003980610c6c5280610c94528061139b5250806101d452806105585280610a925280610d495280610f0b52806118f7525080610c0452806112cc52806114fa52506135e36000f3fe6080604052600436106101a05760003560e01c806384e10a90116100ec578063c9d3dc871161008a578063f5a9838311610064578063f5a98383146104cd578063f5f5ba72146104e2578063f639c12c14610504578063f64cee61146105195761021e565b8063c9d3dc871461048e578063e17f212e146104a3578063e22fdece146104b85761021e565b8063a1077532116100c6578063a107753214610422578063b00c0b7614610437578063b8cca0cf14610457578063c39049e41461046c5761021e565b806384e10a90146103c7578063983963d8146103ed5780639d6a890f146104025761021e565b80635ff270791161015957806367fc40291161013357806367fc4029146103375780636d0e8c34146103575780636e61ab961461037957806374e6310e146103995761021e565b80635ff27079146102eb57806361d027b31461030d57806362354e03146103225761021e565b8063047fc9aa146102235780632dafdbbf1461024e57806333ed77cc146102725780634b13e872146102945780635267a15d146102c15780635aa6e675146102d65761021e565b3661021e5760408051808201909152600d81526c7472656173757279206f6e6c7960981b6020820152336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461021b5760405162461bcd60e51b81526004016102129190613275565b60405180910390fd5b50005b600080fd5b34801561022f57600080fd5b50610238610539565b6040516102459190613223565b60405180910390f35b34801561025a57600080fd5b50610263610548565b604051610245939291906133e8565b34801561027e57600080fd5b5061028761059f565b60405161024591906133c6565b3480156102a057600080fd5b506102b46102af366004612f28565b6105a5565b6040516102459190613363565b3480156102cd57600080fd5b50610238610680565b3480156102e257600080fd5b506102386106a5565b3480156102f757600080fd5b5061030b6103063660046130cc565b61073b565b005b34801561031957600080fd5b50610238610a90565b34801561032e57600080fd5b50610238610ab4565b34801561034357600080fd5b5061030b6103523660046130cc565b610abf565b34801561036357600080fd5b5061036c610ba7565b6040516102459190613237565b34801561038557600080fd5b5061030b6103943660046130f4565b610f96565b3480156103a557600080fd5b506103b96103b43660046130cc565b611142565b6040516102459291906133cf565b3480156103d357600080fd5b506103dc6111e8565b6040516102459594939291906133fe565b3480156103f957600080fd5b50610238611202565b34801561040e57600080fd5b5061030b61041d366004612f28565b611211565b34801561042e57600080fd5b506102386112ca565b34801561044357600080fd5b5061030b610452366004612f44565b6112ee565b34801561046357600080fd5b50610287611399565b34801561047857600080fd5b506104816113bd565b6040516102459190613288565b34801561049a57600080fd5b506102876114d7565b3480156104af57600080fd5b5061036c6114dd565b3480156104c457600080fd5b5061036c6114ed565b3480156104d957600080fd5b5061030b611566565b3480156104ee57600080fd5b506104f7611620565b6040516102459190613275565b34801561051057600080fd5b50610287611647565b34801561052557600080fd5b5061048161053436600461319a565b61165a565b6003546001600160a01b031681565b600080600061058f6004600601547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163161177690919063ffffffff16565b600a549094600094509092509050565b600d5481565b6105ad612d55565b60408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b0382166105f95760405162461bcd60e51b81526004016102129190613275565b506001600160a01b0383166000908152600c60205260409020600281015460ff1661064057805460ff19908116825560786001808401919091556002830180549092161790555b8054839060ff16600181111561065257fe5b9081600181111561065f57fe5b905250600181015460208401526002015460ff161515604083015250919050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166106c8576000546001600160a01b0316610735565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561070857600080fd5b505afa15801561071c573d6000803e3d6000fd5b505050506040513d602081101561073257600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561077f57600080fd5b505afa158015610793573d6000803e3d6000fd5b505050506040513d60208110156107a957600080fd5b50516107ec576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610858576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156108ae576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109485780601f1061091d57610100808354040283529160200191610948565b820191906000526020600020905b81548152906001019060200180831161092b57829003601f168201915b5050506001600160e01b031986166000908152600160208190526040822082815594955090925061097c9150830182612d77565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106109c45780518252601f1990920191602091820191016109a5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610a26576040519150601f19603f3d011682016040523d82523d6000602084013e610a2b565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a1610a8a816117d9565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60076001609c1b0181565b610ac76117f6565b6001600160e01b03198116600090815260016020526040902054610b32576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610ba290830182612d77565b505050565b60035460408051808201909152600c81526b06164647265737320697320360a41b60208201526000916001600160a01b03169081610bf85760405162461bcd60e51b81526004016102129190613275565b50336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c6a576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000001580610cb657507f000000000000000000000000000000000000000000000000000000000000000042105b15610cc45760019150610f92565b600d54610cd05742600d555b610cda6004611857565b610cec57610ce74261185b565b610d1b565b6000610cf86004611ba0565b60020154905080421115610d1957610d19610d14826001611776565b61185b565b505b600b544290610d2d9062015180611776565b11610f8d5742600b819055506000610e7542610ddf60646101907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166397249db76040518163ffffffff1660e01b815260040160206040518083038186803b158015610da057600080fd5b505afa158015610db4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd891906131b2565b9190611c15565b600260009054906101000a90046001600160a01b03166001600160a01b031663c853b8d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e2f57600080fd5b505af1158015610e43573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e6b9190810190612ffb565b6004929190611d23565b90507f83271265e292ba2d92e1eb89cdbda68f1803ae726a27a5afe6a77d6430cddbd581604051610ea691906133c6565b60405180910390a16000610ebb600430611d87565b90507f1f0936062e6ce780790714a1ec5787d290675660a8566059ac9d6cfb2a336eec81604051610eec91906133c6565b60405180910390a160405163ec8d877760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ec8d877790610f409084906004016133c6565b600060405180830381600087803b158015610f5a57600080fd5b505af1158015610f6e573d6000803e3d6000fd5b505050506000610f7e6004611dcf565b9050808214610f8957fe5b5050505b600191505b5090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015283906001600160a01b038216610fe25760405162461bcd60e51b81526004016102129190613275565b50600054600160b01b900460ff16806110055750600054600160a81b900460ff16155b1561113757611012611e38565b600083600181111561102057fe5b14156110ae57604080518082019091526009815268746f707570206c6f7760b81b6020820152606483116110675760405162461bcd60e51b81526004016102129190613275565b5060408051808201909152600a8152690e8dee0eae040d0d2ced60b31b60208201526101908311156110ac5760405162461bcd60e51b81526004016102129190613275565b505b6001600160a01b0384166000908152600c6020526040902080548490829060ff1916600183818111156110dd57fe5b0217905550600180820184905560028201805460ff191690911790556040517fcf085312d79a75faa5f1b9f6bec58a64813338f5e5e5759573cab22c6da2d25b90611129908390613392565b60405180910390a150610a8a565b610a8a600036611e6d565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156111de5780601f106111b3576101008083540402835291602001916111de565b820191906000526020600020905b8154815290600101906020018083116111c157829003601f168201915b5050505050905082565b600754600854600954600a54600654939492939192909190565b6002546001600160a01b031681565b600054600160a01b900460ff1615611267576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b6112f6610680565b6001600160a01b0316336001600160a01b031614611352576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b61138b61138683836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250611ff0565b61211d565b6113958282612141565b5050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6113c5612dbe565b6113cf6004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561149e5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a0830152908352909201910161142d565b50505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081525050905090565b600b5481565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611560576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b61156e6117f6565b600054600160a81b900460ff16156115cd576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600d81526c125b98d95b9d1a5d99541bdbdb609a1b602082015290565b600b546000906107359062015180611776565b611662612dbe565b61166d60048361226b565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561173c5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a083015290835290920191016116cb565b5050509082525060018201546020820152600282015460408201526003820154606082015260049091015460809091015290525092915050565b6000828201838110156117d0576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b3d604051818101604052816000823e82156117f2578181f35b8181fd5b6117fe6106a5565b6001600160a01b0316336001600160a01b031614611855576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b5490565b60035460408051631b73b4cb60e01b815290516000926001600160a01b031691631b73b4cb916004808301926020929190829003018186803b1580156118a057600080fd5b505afa1580156118b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d891906131b2565b600754600a54919250600091611924919061191e906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163190611776565b906122dd565b9050600260009054906101000a90046001600160a01b03166001600160a01b031663981940296040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561197657600080fd5b505af19250505080156119a6575060408051601f3d908101601f191682019092526119a3918101906131b2565b60015b611a09576119b261349f565b806119bd57506119d7565b8060405162461bcd60e51b81526004016102129190613275565b6040518060600160405280602681526020016135676026913960405162461bcd60e51b81526004016102129190613275565b611a1760048584868561233a565b506000611a246004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611af35760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611a82565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090507f677db469fe5eaf40f0415f5433ebc8ebe9ac089662feca0280495fb4c96da29181602001518260400151858460000151856060015160200151866060015160400151876060015160600151886060015160800151604051611b92989796959493929190613421565b60405180910390a150505050565b600080611bac83611857565b11604051806040016040528060088152602001676e6f20616e6e756d60c01b81525090611bec5760405162461bcd60e51b81526004016102129190613275565b5081600001826001015481548110611c0057fe5b90600052602060002090600802019050919050565b6000808211611c5e576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b83611c6b57506000611d1c565b83830283858281611c7857fe5b041415611c9157828181611c8857fe5b04915050611d1c565b6000838681611c9c57fe5b0490506000848781611caa57fe5b0690506000858781611cb857fe5b0490506000868881611cc657fe5b069050611d14611ce088611cda86856123fc565b90612455565b611d0e611ced86866123fc565b611d0e611cfa89876123fc565b611d0e8d611d088c8b6123fc565b906123fc565b90611776565b955050505050505b9392505050565b600080611d2f86611ba0565b60028701546003880154919250611d5891611d4a84896124bc565b6003850192919088886124db565b6003870154909250611d6a9083611776565b6003870181905560028701541015611d7e57fe5b50949350505050565b600080611d9384611ba0565b9050611da26003820184612730565b6004850154909250611db49083611776565b6004850181905560038501541015611dc857fe5b5092915050565b600080611ddb83611ba0565b9050611de981600301612854565b6005840154909250611dfb9083611776565b6005840181905560048401541015611e0f57fe5b6006830154611e1e9083611776565b6006840181905560058401541015611e3257fe5b50919050565b600054600160b01b900460ff1615611e6557333014611e5357fe5b6000805460ff60b01b19169055611855565b6118556117f6565b611e756117f6565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b03198616815260016020818152604090922084518155848301518051919450611f6b93928501920190612deb565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b8381101561203457818101518382015260200161201c565b50505050905090810190601f1680156120615780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b86518110156120c95786818151811061209757fe5b60200260200101518314156120c1578581815181106120b257fe5b602002602001015191506120c9565b600101612082565b506001600160a01b038116612114576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600061216c838360405180604001604052806006815260200165537570706c7960d01b815250611ff0565b6003546040519192507f9a9b245c8db671c90d6db95f7ff0c18c15378a1d55ee4aea21759be8ad27d30e916121ac916001600160a01b031690849061325b565b60405180910390a1600380546001600160a01b0319166001600160a01b03831617905560408051808201909152601781527f496e63656e74697665506f6f6c416c6c6f636174696f6e00000000000000000060208201526122109084908490611ff0565b600280546001600160a01b0319166001600160a01b0392831617908190556040517f8c42cf8a1561f290fbb07d1ff00cab15929cf29ebc85adb0b8aaee1cd57be7ec9261225e921690613223565b60405180910390a1505050565b600061227683611857565b8210604051806040016040528060088152602001676e6f20616e6e756d60c01b815250906122b75760405162461bcd60e51b81526004016102129190613275565b508260000182815481106122c757fe5b9060005260206000209060080201905092915050565b600082821115612334576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600061234586611857565b111561239c5761235485611ba0565b60020154841160405180604001604052806009815260200168746f6f206561726c7960b81b8152509061239a5760405162461bcd60e51b81526004016102129190613275565b505b84546001810186556000868152602090206008909102016123c081868686866129fe565b805460028701546123d091611776565b60028701558554600110156123f4576001868101546123ee91611776565b60018701555b505050505050565b60008261240b575060006117d3565b8282028284828161241857fe5b04146117d05760405162461bcd60e51b815260040180806020018281038252602181526020018061358d6021913960400191505060405180910390fd5b60008082116124ab576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816124b457fe5b049392505050565b600082600201548211156124cc57fe5b6117d06001611d0e8585612a2a565b60008151600014156124ef57506000612726565b600061250861250286611cda8a8a6122dd565b85612a56565b600189015490925082915061251d9082611776565b600189015561271060005b845181101561272257600061255f86838151811061254257fe5b6020026020010151602001518486611c159092919063ffffffff16565b905061256b84826122dd565b935061259786838151811061257c57fe5b602002602001015160200151846122dd90919063ffffffff16565b92506000806125bd8d8986815181106125ac57fe5b602002602001015160000151612a6c565b9150915081156126015760008d60000182815481106125d857fe5b906000526020600020906006020190506125fb8482612acf90919063ffffffff16565b50612652565b8c54600181018e5560008e815260209020895160069092020190612646908a908790811061262b57fe5b60200260200101516000015182612aeb90919063ffffffff16565b6126508185612acf565b505b87848151811061265e57fe5b6020026020010151600001516001600160a01b031663de6feb78846040518263ffffffff1660e01b815260040161269591906133c6565b600060405180830381600087803b1580156126af57600080fd5b505af11580156126c3573d6000803e3d6000fd5b505050507f7783f810e61c0050d5bcac23752779876844351f2984c24b51c19f7f949c8e498885815181106126f457fe5b6020026020010151600001518460405161270f929190613242565b60405180910390a1505050600101612528565b5050505b9695505050505050565b6000805b8354811015612830576000836001600160a01b0316634b13e87286600001848154811061275d57fe5b60009182526020909120600690910201546040516001600160e01b031960e084901b168152612798916001600160a01b031690600401613223565b606060405180830381600087803b1580156127b257600080fd5b505af11580156127c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ea9190613134565b905061282561281e8287600001858154811061280257fe5b9060005260206000209060060201612b2c90919063ffffffff16565b8490611776565b925050600101612734565b5060028301546128409082611776565b60028401819055600184015410156117d357fe5b6000805b8254811015611e3257600061288884600001838154811061287557fe5b9060005260206000209060060201612c7a565b90506128b98185600001848154811061289d57fe5b9060005260206000209060060201612c9790919063ffffffff16565b60038401546128c89082611776565b600385015583548490839081106128db57fe5b6000918252602082206006909102015460408051630a763c4b60e31b815290516001600160a01b03909216926353b1e258928592600480820193929182900301818588803b15801561292c57600080fd5b505af1158015612940573d6000803e3d6000fd5b50505050506129748185600001848154811061295857fe5b9060005260206000209060060201612cb290919063ffffffff16565b60048401546129839082611776565b60048501556129928382611776565b92507f14539bbe7bf8bc27c7dd3cd8f969ee5ed76f196818aebbeb71de02ac27183a678460000183815481106129c457fe5b60009182526020909120600690910201546040516129ed916001600160a01b0316908490613242565b60405180910390a150600101612858565b60018501849055612a10838383612ccd565b8555612a1b84612cfd565b85600201819055505050505050565b600282015460009080831115612a445760009150506117d3565b612a4e8382612d15565b9150506117d3565b6000818310612a6557816117d0565b5090919050565b600080805b8454811015612ac757836001600160a01b0316856000018281548110612a9357fe5b60009182526020909120600690910201546001600160a01b03161415612abf5780915060019250612ac7565b600101612a71565b509250929050565b6001820154612ade9082611776565b6001830155600290910155565b81546001600160a01b0319166001600160a01b0391909116178155600060018201819055600282018190556003820181905560048201819055600590910155565b81546000906001600160a01b0316318183516001811115612b4957fe5b1415612be45760208301516002850154600091612b6891906064611c15565b9050600082821115612b8157612b7e82846122dd565b90505b6000612b8c87612c7a565b905081811115612b9f5760009450612bac565b612ba982826122dd565b94505b6000612bcd886004015461191e848b600101546122dd90919063ffffffff16565b905080861115612bdb578095505b50505050612c19565b600183516001811115612bf357fe5b1415612c135760038401546001850154612c0c916122dd565b9150612c19565b60009150fe5b6003840154612c289083611776565b600385015583546040517fd6c57656fb4211e1e1ca98fb5da438e294ee525b0eb501a7c143163416013da491612c6b916001600160a01b03909116908590613242565b60405180910390a15092915050565b60006117d3826004015483600301546122dd90919063ffffffff16565b6004820154612ca69082611776565b82600401819055505050565b6005820154612cc19082611776565b82600501819055505050565b6000612cf5612ce084846201d4c0611c15565b612cf0866103e86201d4c0611c15565b612a56565b949350505050565b60006117d36001612d0f84601e612d30565b90612d45565b600081831115612d2457600080fd5b620151808383036124b4565b6201518081028201828110156117d357600080fd5b808203828111156117d357600080fd5b6040805160608101909152806000815260006020820181905260409091015290565b50805460018160011615610100020316600290046000825580601f10612d9d5750612dbb565b601f016020900490600052602060002090810190612dbb9190612e6f565b50565b6040518060800160405280600081526020016000815260200160008152602001612de6612e84565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612e215760008555612e67565b82601f10612e3a57805160ff1916838001178555612e67565b82800160010185558215612e67579182015b82811115612e67578251825591602001919060010190612e4c565b50610f929291505b5b80821115610f925760008155600101612e70565b6040518060a0016040528060608152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612ec3578081fd5b81356020612ed8612ed38361347b565b613457565b8281528181019085830183850287018401881015612ef4578586fd5b855b85811015612f1b578135612f0981613544565b84529284019290840190600101612ef6565b5090979650505050505050565b600060208284031215612f39578081fd5b81356117d081613544565b60008060408385031215612f56578081fd5b823567ffffffffffffffff80821115612f6d578283fd5b818501915085601f830112612f80578283fd5b81356020612f90612ed38361347b565b82815281810190858301838502870184018b1015612fac578788fd5b8796505b84871015612fce578035835260019690960195918301918301612fb0565b5096505086013592505080821115612fe4578283fd5b50612ff185828601612eb3565b9150509250929050565b6000602080838503121561300d578182fd5b825167ffffffffffffffff80821115613024578384fd5b818501915085601f830112613037578384fd5b8151613045612ed38261347b565b818152848101908486016040808502870188018b1015613063578889fd5b8896505b848710156130bd5780828c03121561307d578889fd5b8051818101818110888211171561309057fe5b8252825161309d81613544565b815282890151898201528452600196909601959287019290810190613067565b50909998505050505050505050565b6000602082840312156130dd578081fd5b81356001600160e01b0319811681146117d0578182fd5b600080600060608486031215613108578081fd5b833561311381613544565b9250602084013561312381613559565b929592945050506040919091013590565b600060608284031215613145578081fd5b6040516060810181811067ffffffffffffffff8211171561316257fe5b604052825161317081613559565b8152602083810151908201526040830151801515811461318e578283fd5b60408201529392505050565b6000602082840312156131ab578081fd5b5035919050565b6000602082840312156131c3578081fd5b5051919050565b60008151808452815b818110156131ef576020818501810151868301820152016131d3565b818111156132005782602083870101525b50601f01601f19169290920160200192915050565b6002811061321f57fe5b9052565b6001600160a01b0391909116815260200190565b901515815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6000602082526117d060208301846131ca565b6000602080835260a0845182850152818501516040818187015280870151915060608281880152808801519250608080818901526101408801845186878b01528181518084526101608c01915089830193508a92505b8083101561333257835180516001600160a01b031683528a8101518b84015287810151888401528681015187840152858101518684015289015189830152928901926001929092019160c0909101906132de565b509786015160c08b015250509183015160e08801528201516101008701520151610120909401939093529392505050565b6000606082019050613376828451613215565b6020830151602083015260408301511515604083015292915050565b60006060820190506133a88260ff855416613215565b6001830154602083015260029092015460ff16151560409091015290565b90815260200190565b600083825260406020830152612cf560408301846131ca565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405181810167ffffffffffffffff8111828210171561347357fe5b604052919050565b600067ffffffffffffffff82111561348f57fe5b5060209081020190565b60e01c90565b600060443d10156134af57610738565b600481823e6308c379a06134c38251613499565b146134cd57610738565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156134fd5750505050610738565b828401925082519150808211156135175750505050610738565b503d8301602082840101111561352f57505050610738565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114612dbb57600080fd5b60028110612dbb57600080fdfe756e6b6e6f776e206572726f722e20676574416e6e75616c50657263656e7461676542697073536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220503e0222a79264355967f4c67519a30dc1b722f4bec55571c70b3e49263e6d2464736f6c634300070600330000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b00000000000000000000000010000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000063718500
Deployed ByteCode
0x6080604052600436106101a05760003560e01c806384e10a90116100ec578063c9d3dc871161008a578063f5a9838311610064578063f5a98383146104cd578063f5f5ba72146104e2578063f639c12c14610504578063f64cee61146105195761021e565b8063c9d3dc871461048e578063e17f212e146104a3578063e22fdece146104b85761021e565b8063a1077532116100c6578063a107753214610422578063b00c0b7614610437578063b8cca0cf14610457578063c39049e41461046c5761021e565b806384e10a90146103c7578063983963d8146103ed5780639d6a890f146104025761021e565b80635ff270791161015957806367fc40291161013357806367fc4029146103375780636d0e8c34146103575780636e61ab961461037957806374e6310e146103995761021e565b80635ff27079146102eb57806361d027b31461030d57806362354e03146103225761021e565b8063047fc9aa146102235780632dafdbbf1461024e57806333ed77cc146102725780634b13e872146102945780635267a15d146102c15780635aa6e675146102d65761021e565b3661021e5760408051808201909152600d81526c7472656173757279206f6e6c7960981b6020820152336001600160a01b037f0000000000000000000000001000000000000000000000000000000000000005161461021b5760405162461bcd60e51b81526004016102129190613275565b60405180910390fd5b50005b600080fd5b34801561022f57600080fd5b50610238610539565b6040516102459190613223565b60405180910390f35b34801561025a57600080fd5b50610263610548565b604051610245939291906133e8565b34801561027e57600080fd5b5061028761059f565b60405161024591906133c6565b3480156102a057600080fd5b506102b46102af366004612f28565b6105a5565b6040516102459190613363565b3480156102cd57600080fd5b50610238610680565b3480156102e257600080fd5b506102386106a5565b3480156102f757600080fd5b5061030b6103063660046130cc565b61073b565b005b34801561031957600080fd5b50610238610a90565b34801561032e57600080fd5b50610238610ab4565b34801561034357600080fd5b5061030b6103523660046130cc565b610abf565b34801561036357600080fd5b5061036c610ba7565b6040516102459190613237565b34801561038557600080fd5b5061030b6103943660046130f4565b610f96565b3480156103a557600080fd5b506103b96103b43660046130cc565b611142565b6040516102459291906133cf565b3480156103d357600080fd5b506103dc6111e8565b6040516102459594939291906133fe565b3480156103f957600080fd5b50610238611202565b34801561040e57600080fd5b5061030b61041d366004612f28565b611211565b34801561042e57600080fd5b506102386112ca565b34801561044357600080fd5b5061030b610452366004612f44565b6112ee565b34801561046357600080fd5b50610287611399565b34801561047857600080fd5b506104816113bd565b6040516102459190613288565b34801561049a57600080fd5b506102876114d7565b3480156104af57600080fd5b5061036c6114dd565b3480156104c457600080fd5b5061036c6114ed565b3480156104d957600080fd5b5061030b611566565b3480156104ee57600080fd5b506104f7611620565b6040516102459190613275565b34801561051057600080fd5b50610287611647565b34801561052557600080fd5b5061048161053436600461319a565b61165a565b6003546001600160a01b031681565b600080600061058f6004600601547f00000000000000000000000010000000000000000000000000000000000000056001600160a01b03163161177690919063ffffffff16565b600a549094600094509092509050565b600d5481565b6105ad612d55565b60408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b0382166105f95760405162461bcd60e51b81526004016102129190613275565b506001600160a01b0383166000908152600c60205260409020600281015460ff1661064057805460ff19908116825560786001808401919091556002830180549092161790555b8054839060ff16600181111561065257fe5b9081600181111561065f57fe5b905250600181015460208401526002015460ff161515604083015250919050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166106c8576000546001600160a01b0316610735565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561070857600080fd5b505afa15801561071c573d6000803e3d6000fd5b505050506040513d602081101561073257600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561077f57600080fd5b505afa158015610793573d6000803e3d6000fd5b505050506040513d60208110156107a957600080fd5b50516107ec576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610858576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156108ae576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109485780601f1061091d57610100808354040283529160200191610948565b820191906000526020600020905b81548152906001019060200180831161092b57829003601f168201915b5050506001600160e01b031986166000908152600160208190526040822082815594955090925061097c9150830182612d77565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106109c45780518252601f1990920191602091820191016109a5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610a26576040519150601f19603f3d011682016040523d82523d6000602084013e610a2b565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a1610a8a816117d9565b50505050565b7f000000000000000000000000100000000000000000000000000000000000000581565b60076001609c1b0181565b610ac76117f6565b6001600160e01b03198116600090815260016020526040902054610b32576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610ba290830182612d77565b505050565b60035460408051808201909152600c81526b06164647265737320697320360a41b60208201526000916001600160a01b03169081610bf85760405162461bcd60e51b81526004016102129190613275565b50336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614610c6a576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000637185001580610cb657507f000000000000000000000000000000000000000000000000000000006371850042105b15610cc45760019150610f92565b600d54610cd05742600d555b610cda6004611857565b610cec57610ce74261185b565b610d1b565b6000610cf86004611ba0565b60020154905080421115610d1957610d19610d14826001611776565b61185b565b505b600b544290610d2d9062015180611776565b11610f8d5742600b819055506000610e7542610ddf60646101907f00000000000000000000000010000000000000000000000000000000000000056001600160a01b03166397249db76040518163ffffffff1660e01b815260040160206040518083038186803b158015610da057600080fd5b505afa158015610db4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd891906131b2565b9190611c15565b600260009054906101000a90046001600160a01b03166001600160a01b031663c853b8d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e2f57600080fd5b505af1158015610e43573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e6b9190810190612ffb565b6004929190611d23565b90507f83271265e292ba2d92e1eb89cdbda68f1803ae726a27a5afe6a77d6430cddbd581604051610ea691906133c6565b60405180910390a16000610ebb600430611d87565b90507f1f0936062e6ce780790714a1ec5787d290675660a8566059ac9d6cfb2a336eec81604051610eec91906133c6565b60405180910390a160405163ec8d877760e01b81526001600160a01b037f0000000000000000000000001000000000000000000000000000000000000005169063ec8d877790610f409084906004016133c6565b600060405180830381600087803b158015610f5a57600080fd5b505af1158015610f6e573d6000803e3d6000fd5b505050506000610f7e6004611dcf565b9050808214610f8957fe5b5050505b600191505b5090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015283906001600160a01b038216610fe25760405162461bcd60e51b81526004016102129190613275565b50600054600160b01b900460ff16806110055750600054600160a81b900460ff16155b1561113757611012611e38565b600083600181111561102057fe5b14156110ae57604080518082019091526009815268746f707570206c6f7760b81b6020820152606483116110675760405162461bcd60e51b81526004016102129190613275565b5060408051808201909152600a8152690e8dee0eae040d0d2ced60b31b60208201526101908311156110ac5760405162461bcd60e51b81526004016102129190613275565b505b6001600160a01b0384166000908152600c6020526040902080548490829060ff1916600183818111156110dd57fe5b0217905550600180820184905560028201805460ff191690911790556040517fcf085312d79a75faa5f1b9f6bec58a64813338f5e5e5759573cab22c6da2d25b90611129908390613392565b60405180910390a150610a8a565b610a8a600036611e6d565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156111de5780601f106111b3576101008083540402835291602001916111de565b820191906000526020600020905b8154815290600101906020018083116111c157829003601f168201915b5050505050905082565b600754600854600954600a54600654939492939192909190565b6002546001600160a01b031681565b600054600160a01b900460ff1615611267576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000100000000000000000000000000000000000000281565b6112f6610680565b6001600160a01b0316336001600160a01b031614611352576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b61138b61138683836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250611ff0565b61211d565b6113958282612141565b5050565b7f000000000000000000000000000000000000000000000000000000006371850081565b6113c5612dbe565b6113cf6004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561149e5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a0830152908352909201910161142d565b50505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081525050905090565b600b5481565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614611560576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b61156e6117f6565b600054600160a81b900460ff16156115cd576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600d81526c125b98d95b9d1a5d99541bdbdb609a1b602082015290565b600b546000906107359062015180611776565b611662612dbe565b61166d60048361226b565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561173c5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a083015290835290920191016116cb565b5050509082525060018201546020820152600282015460408201526003820154606082015260049091015460809091015290525092915050565b6000828201838110156117d0576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b3d604051818101604052816000823e82156117f2578181f35b8181fd5b6117fe6106a5565b6001600160a01b0316336001600160a01b031614611855576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b5490565b60035460408051631b73b4cb60e01b815290516000926001600160a01b031691631b73b4cb916004808301926020929190829003018186803b1580156118a057600080fd5b505afa1580156118b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d891906131b2565b600754600a54919250600091611924919061191e906001600160a01b037f0000000000000000000000001000000000000000000000000000000000000005163190611776565b906122dd565b9050600260009054906101000a90046001600160a01b03166001600160a01b031663981940296040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561197657600080fd5b505af19250505080156119a6575060408051601f3d908101601f191682019092526119a3918101906131b2565b60015b611a09576119b261349f565b806119bd57506119d7565b8060405162461bcd60e51b81526004016102129190613275565b6040518060600160405280602681526020016135676026913960405162461bcd60e51b81526004016102129190613275565b611a1760048584868561233a565b506000611a246004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611af35760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611a82565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090507f677db469fe5eaf40f0415f5433ebc8ebe9ac089662feca0280495fb4c96da29181602001518260400151858460000151856060015160200151866060015160400151876060015160600151886060015160800151604051611b92989796959493929190613421565b60405180910390a150505050565b600080611bac83611857565b11604051806040016040528060088152602001676e6f20616e6e756d60c01b81525090611bec5760405162461bcd60e51b81526004016102129190613275565b5081600001826001015481548110611c0057fe5b90600052602060002090600802019050919050565b6000808211611c5e576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b83611c6b57506000611d1c565b83830283858281611c7857fe5b041415611c9157828181611c8857fe5b04915050611d1c565b6000838681611c9c57fe5b0490506000848781611caa57fe5b0690506000858781611cb857fe5b0490506000868881611cc657fe5b069050611d14611ce088611cda86856123fc565b90612455565b611d0e611ced86866123fc565b611d0e611cfa89876123fc565b611d0e8d611d088c8b6123fc565b906123fc565b90611776565b955050505050505b9392505050565b600080611d2f86611ba0565b60028701546003880154919250611d5891611d4a84896124bc565b6003850192919088886124db565b6003870154909250611d6a9083611776565b6003870181905560028701541015611d7e57fe5b50949350505050565b600080611d9384611ba0565b9050611da26003820184612730565b6004850154909250611db49083611776565b6004850181905560038501541015611dc857fe5b5092915050565b600080611ddb83611ba0565b9050611de981600301612854565b6005840154909250611dfb9083611776565b6005840181905560048401541015611e0f57fe5b6006830154611e1e9083611776565b6006840181905560058401541015611e3257fe5b50919050565b600054600160b01b900460ff1615611e6557333014611e5357fe5b6000805460ff60b01b19169055611855565b6118556117f6565b611e756117f6565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b03198616815260016020818152604090922084518155848301518051919450611f6b93928501920190612deb565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b8381101561203457818101518382015260200161201c565b50505050905090810190601f1680156120615780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b86518110156120c95786818151811061209757fe5b60200260200101518314156120c1578581815181106120b257fe5b602002602001015191506120c9565b600101612082565b506001600160a01b038116612114576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600061216c838360405180604001604052806006815260200165537570706c7960d01b815250611ff0565b6003546040519192507f9a9b245c8db671c90d6db95f7ff0c18c15378a1d55ee4aea21759be8ad27d30e916121ac916001600160a01b031690849061325b565b60405180910390a1600380546001600160a01b0319166001600160a01b03831617905560408051808201909152601781527f496e63656e74697665506f6f6c416c6c6f636174696f6e00000000000000000060208201526122109084908490611ff0565b600280546001600160a01b0319166001600160a01b0392831617908190556040517f8c42cf8a1561f290fbb07d1ff00cab15929cf29ebc85adb0b8aaee1cd57be7ec9261225e921690613223565b60405180910390a1505050565b600061227683611857565b8210604051806040016040528060088152602001676e6f20616e6e756d60c01b815250906122b75760405162461bcd60e51b81526004016102129190613275565b508260000182815481106122c757fe5b9060005260206000209060080201905092915050565b600082821115612334576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600061234586611857565b111561239c5761235485611ba0565b60020154841160405180604001604052806009815260200168746f6f206561726c7960b81b8152509061239a5760405162461bcd60e51b81526004016102129190613275565b505b84546001810186556000868152602090206008909102016123c081868686866129fe565b805460028701546123d091611776565b60028701558554600110156123f4576001868101546123ee91611776565b60018701555b505050505050565b60008261240b575060006117d3565b8282028284828161241857fe5b04146117d05760405162461bcd60e51b815260040180806020018281038252602181526020018061358d6021913960400191505060405180910390fd5b60008082116124ab576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816124b457fe5b049392505050565b600082600201548211156124cc57fe5b6117d06001611d0e8585612a2a565b60008151600014156124ef57506000612726565b600061250861250286611cda8a8a6122dd565b85612a56565b600189015490925082915061251d9082611776565b600189015561271060005b845181101561272257600061255f86838151811061254257fe5b6020026020010151602001518486611c159092919063ffffffff16565b905061256b84826122dd565b935061259786838151811061257c57fe5b602002602001015160200151846122dd90919063ffffffff16565b92506000806125bd8d8986815181106125ac57fe5b602002602001015160000151612a6c565b9150915081156126015760008d60000182815481106125d857fe5b906000526020600020906006020190506125fb8482612acf90919063ffffffff16565b50612652565b8c54600181018e5560008e815260209020895160069092020190612646908a908790811061262b57fe5b60200260200101516000015182612aeb90919063ffffffff16565b6126508185612acf565b505b87848151811061265e57fe5b6020026020010151600001516001600160a01b031663de6feb78846040518263ffffffff1660e01b815260040161269591906133c6565b600060405180830381600087803b1580156126af57600080fd5b505af11580156126c3573d6000803e3d6000fd5b505050507f7783f810e61c0050d5bcac23752779876844351f2984c24b51c19f7f949c8e498885815181106126f457fe5b6020026020010151600001518460405161270f929190613242565b60405180910390a1505050600101612528565b5050505b9695505050505050565b6000805b8354811015612830576000836001600160a01b0316634b13e87286600001848154811061275d57fe5b60009182526020909120600690910201546040516001600160e01b031960e084901b168152612798916001600160a01b031690600401613223565b606060405180830381600087803b1580156127b257600080fd5b505af11580156127c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ea9190613134565b905061282561281e8287600001858154811061280257fe5b9060005260206000209060060201612b2c90919063ffffffff16565b8490611776565b925050600101612734565b5060028301546128409082611776565b60028401819055600184015410156117d357fe5b6000805b8254811015611e3257600061288884600001838154811061287557fe5b9060005260206000209060060201612c7a565b90506128b98185600001848154811061289d57fe5b9060005260206000209060060201612c9790919063ffffffff16565b60038401546128c89082611776565b600385015583548490839081106128db57fe5b6000918252602082206006909102015460408051630a763c4b60e31b815290516001600160a01b03909216926353b1e258928592600480820193929182900301818588803b15801561292c57600080fd5b505af1158015612940573d6000803e3d6000fd5b50505050506129748185600001848154811061295857fe5b9060005260206000209060060201612cb290919063ffffffff16565b60048401546129839082611776565b60048501556129928382611776565b92507f14539bbe7bf8bc27c7dd3cd8f969ee5ed76f196818aebbeb71de02ac27183a678460000183815481106129c457fe5b60009182526020909120600690910201546040516129ed916001600160a01b0316908490613242565b60405180910390a150600101612858565b60018501849055612a10838383612ccd565b8555612a1b84612cfd565b85600201819055505050505050565b600282015460009080831115612a445760009150506117d3565b612a4e8382612d15565b9150506117d3565b6000818310612a6557816117d0565b5090919050565b600080805b8454811015612ac757836001600160a01b0316856000018281548110612a9357fe5b60009182526020909120600690910201546001600160a01b03161415612abf5780915060019250612ac7565b600101612a71565b509250929050565b6001820154612ade9082611776565b6001830155600290910155565b81546001600160a01b0319166001600160a01b0391909116178155600060018201819055600282018190556003820181905560048201819055600590910155565b81546000906001600160a01b0316318183516001811115612b4957fe5b1415612be45760208301516002850154600091612b6891906064611c15565b9050600082821115612b8157612b7e82846122dd565b90505b6000612b8c87612c7a565b905081811115612b9f5760009450612bac565b612ba982826122dd565b94505b6000612bcd886004015461191e848b600101546122dd90919063ffffffff16565b905080861115612bdb578095505b50505050612c19565b600183516001811115612bf357fe5b1415612c135760038401546001850154612c0c916122dd565b9150612c19565b60009150fe5b6003840154612c289083611776565b600385015583546040517fd6c57656fb4211e1e1ca98fb5da438e294ee525b0eb501a7c143163416013da491612c6b916001600160a01b03909116908590613242565b60405180910390a15092915050565b60006117d3826004015483600301546122dd90919063ffffffff16565b6004820154612ca69082611776565b82600401819055505050565b6005820154612cc19082611776565b82600501819055505050565b6000612cf5612ce084846201d4c0611c15565b612cf0866103e86201d4c0611c15565b612a56565b949350505050565b60006117d36001612d0f84601e612d30565b90612d45565b600081831115612d2457600080fd5b620151808383036124b4565b6201518081028201828110156117d357600080fd5b808203828111156117d357600080fd5b6040805160608101909152806000815260006020820181905260409091015290565b50805460018160011615610100020316600290046000825580601f10612d9d5750612dbb565b601f016020900490600052602060002090810190612dbb9190612e6f565b50565b6040518060800160405280600081526020016000815260200160008152602001612de6612e84565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612e215760008555612e67565b82601f10612e3a57805160ff1916838001178555612e67565b82800160010185558215612e67579182015b82811115612e67578251825591602001919060010190612e4c565b50610f929291505b5b80821115610f925760008155600101612e70565b6040518060a0016040528060608152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612ec3578081fd5b81356020612ed8612ed38361347b565b613457565b8281528181019085830183850287018401881015612ef4578586fd5b855b85811015612f1b578135612f0981613544565b84529284019290840190600101612ef6565b5090979650505050505050565b600060208284031215612f39578081fd5b81356117d081613544565b60008060408385031215612f56578081fd5b823567ffffffffffffffff80821115612f6d578283fd5b818501915085601f830112612f80578283fd5b81356020612f90612ed38361347b565b82815281810190858301838502870184018b1015612fac578788fd5b8796505b84871015612fce578035835260019690960195918301918301612fb0565b5096505086013592505080821115612fe4578283fd5b50612ff185828601612eb3565b9150509250929050565b6000602080838503121561300d578182fd5b825167ffffffffffffffff80821115613024578384fd5b818501915085601f830112613037578384fd5b8151613045612ed38261347b565b818152848101908486016040808502870188018b1015613063578889fd5b8896505b848710156130bd5780828c03121561307d578889fd5b8051818101818110888211171561309057fe5b8252825161309d81613544565b815282890151898201528452600196909601959287019290810190613067565b50909998505050505050505050565b6000602082840312156130dd578081fd5b81356001600160e01b0319811681146117d0578182fd5b600080600060608486031215613108578081fd5b833561311381613544565b9250602084013561312381613559565b929592945050506040919091013590565b600060608284031215613145578081fd5b6040516060810181811067ffffffffffffffff8211171561316257fe5b604052825161317081613559565b8152602083810151908201526040830151801515811461318e578283fd5b60408201529392505050565b6000602082840312156131ab578081fd5b5035919050565b6000602082840312156131c3578081fd5b5051919050565b60008151808452815b818110156131ef576020818501810151868301820152016131d3565b818111156132005782602083870101525b50601f01601f19169290920160200192915050565b6002811061321f57fe5b9052565b6001600160a01b0391909116815260200190565b901515815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6000602082526117d060208301846131ca565b6000602080835260a0845182850152818501516040818187015280870151915060608281880152808801519250608080818901526101408801845186878b01528181518084526101608c01915089830193508a92505b8083101561333257835180516001600160a01b031683528a8101518b84015287810151888401528681015187840152858101518684015289015189830152928901926001929092019160c0909101906132de565b509786015160c08b015250509183015160e08801528201516101008701520151610120909401939093529392505050565b6000606082019050613376828451613215565b6020830151602083015260408301511515604083015292915050565b60006060820190506133a88260ff855416613215565b6001830154602083015260029092015460ff16151560409091015290565b90815260200190565b600083825260406020830152612cf560408301846131ca565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405181810167ffffffffffffffff8111828210171561347357fe5b604052919050565b600067ffffffffffffffff82111561348f57fe5b5060209081020190565b60e01c90565b600060443d10156134af57610738565b600481823e6308c379a06134c38251613499565b146134cd57610738565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156134fd5750505050610738565b828401925082519150808211156135175750505050610738565b503d8301602082840101111561352f57505050610738565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114612dbb57600080fd5b60028110612dbb57600080fdfe756e6b6e6f776e206572726f722e20676574416e6e75616c50657263656e7461676542697073536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220503e0222a79264355967f4c67519a30dc1b722f4bec55571c70b3e49263e6d2464736f6c63430007060033