Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- FlareDaemon
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2022-02-22T12:08:50.157588Z
Contract source code
// Sources flattened with hardhat v2.3.0 https://hardhat.org pragma abicoder v2; // File contracts/governance/implementation/GovernedBase.sol // SPDX-License-Identifier: MIT pragma solidity 0.7.6; /** * @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 { address public governance; address public proposedGovernance; bool private initialised; event GovernanceProposed(address proposedGovernance); event GovernanceUpdated (address oldGovernance, address newGoveranance); modifier onlyGovernance () { require (msg.sender == governance, "only governance"); _; } constructor(address _governance) { if (_governance != address(0)) { initialise(_governance); } } /** * @notice First of a two step process for turning over governance to another address. * @param _governance The address to propose to receive governance role. * @dev Must hold governance to propose another address. */ function proposeGovernance(address _governance) external onlyGovernance { proposedGovernance = _governance; emit GovernanceProposed(_governance); } /** * @notice Once proposed, claimant can claim the governance role as the second of a two-step process. */ function claimGovernance() external { require(msg.sender == proposedGovernance, "not claimaint"); emit GovernanceUpdated(governance, proposedGovernance); governance = proposedGovernance; proposedGovernance = address(0); } /** * @notice In a one-step process, turn over governance to another address. * @dev Must hold governance to transfer. */ function transferGovernance(address _governance) external onlyGovernance { emit GovernanceUpdated(governance, _governance); governance = _governance; proposedGovernance = address(0); } /** * @notice Initialize the governance address if not first initialized. */ function initialise(address _governance) public virtual { require(initialised == false, "initialised != false"); initialised = true; emit GovernanceUpdated(governance, _governance); governance = _governance; proposedGovernance = address(0); } } // File contracts/governance/implementation/GovernedAtGenesis.sol // pragma solidity 0.7.6; /** * @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); } } // File contracts/genesis/interface/IInflationGenesis.sol // pragma solidity 0.7.6; 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; } // File contracts/genesis/interface/IFlareDaemonize.sol // pragma solidity 0.7.6; /// 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); } // File @openzeppelin/contracts/math/[email protected] // 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; } } // File contracts/utils/implementation/SafePct.sol // pragma solidity 0.7.6; /** * @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)); } } // File contracts/genesis/implementation/FlareDaemon.sol // // 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; /** * @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 { 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_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 - 50 million native token uint256 internal constant MAX_MINTING_REQUEST_DEFAULT = 50000000 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 This modifier ensures that this contract's balance matches the expected balance. */ modifier mustBalance { _; // 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); } } /** * @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)) { /* 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[] calldata _registrations) external onlyGovernance { // 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 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 inflation contract, which will receive minted inflation funds for funding to * rewarding contracts. * @param _inflation The inflation contract. */ function setInflation(IInflationGenesis _inflation) external onlyGovernance { require(address(_inflation) != address(0), ERR_INFLATION_ZERO); emit InflationSet(_inflation, inflation); inflation = _inflation; if (maxMintingRequestWei == 0) { maxMintingRequestWei = MAX_MINTING_REQUEST_DEFAULT; } } /** * @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 mustBalance onlySystemTrigger returns (uint256 _toMintWei) { return triggerInternal(); } /** * @notice Unregister all contracts from being polled by the daemon process. */ function unregisterAll() external onlyGovernance { _unregisterAll(); } 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 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; } lastBalance = address(this).balance; } 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 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); } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"ContractDaemonizeErrored","inputs":[{"type":"address","name":"theContract","internalType":"address","indexed":false},{"type":"uint256","name":"atBlock","internalType":"uint256","indexed":false},{"type":"string","name":"theMessage","internalType":"string","indexed":false},{"type":"uint256","name":"gasConsumed","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContractDaemonized","inputs":[{"type":"address","name":"theContract","internalType":"address","indexed":false},{"type":"uint256","name":"gasConsumed","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContractHeldOff","inputs":[{"type":"address","name":"theContract","internalType":"address","indexed":false},{"type":"uint256","name":"blockHoldoffsRemaining","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContractsSkippedOutOfGas","inputs":[{"type":"uint256","name":"numberOfSkippedConstracts","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceProposed","inputs":[{"type":"address","name":"proposedGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceUpdated","inputs":[{"type":"address","name":"oldGovernance","internalType":"address","indexed":false},{"type":"address","name":"newGoveranance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"InflationSet","inputs":[{"type":"address","name":"theNewContract","internalType":"contract IInflationGenesis","indexed":false},{"type":"address","name":"theOldContract","internalType":"contract IInflationGenesis","indexed":false}],"anonymous":false},{"type":"event","name":"MintingReceived","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MintingRequestReceived","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MintingRequestTriggered","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MintingWithdrawn","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RegistrationUpdated","inputs":[{"type":"address","name":"theContract","internalType":"contract IFlareDaemonize","indexed":false},{"type":"bool","name":"add","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SelfDestructReceived","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"blockHoldoff","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimGovernance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint192","name":"totalDaemonizedErrors","internalType":"uint192"},{"type":"uint64","name":"lastErrorTypeIndex","internalType":"uint64"}],"name":"errorData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_daemonizeContracts","internalType":"contract IFlareDaemonize[]"},{"type":"uint256[]","name":"_gasLimits","internalType":"uint256[]"},{"type":"uint256[]","name":"_blockHoldoffsRemaining","internalType":"uint256[]"}],"name":"getDaemonizedContractsData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNextMintRequestAllowedTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IInflationGenesis"}],"name":"inflation","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"initialiseFixedAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastMintRequestTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastUpdateMaxMintRequestTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxMintingRequestWei","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"proposeGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"proposedGovernance","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"registerToDaemonize","inputs":[{"type":"tuple[]","name":"_registrations","internalType":"struct FlareDaemon.Registration[]","components":[{"type":"address","name":"daemonizedContract","internalType":"contract IFlareDaemonize"},{"type":"uint256","name":"gasLimit","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestMinting","inputs":[{"type":"uint256","name":"_amountWei","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBlockHoldoff","inputs":[{"type":"uint256","name":"_blockHoldoff","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setInflation","inputs":[{"type":"address","name":"_inflation","internalType":"contract IInflationGenesis"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxMintingRequest","inputs":[{"type":"uint256","name":"_maxMintingRequestWei","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_lastErrorBlock","internalType":"uint256[]"},{"type":"uint256[]","name":"_numErrors","internalType":"uint256[]"},{"type":"string[]","name":"_errorString","internalType":"string[]"},{"type":"address[]","name":"_erroringContract","internalType":"address[]"},{"type":"uint256","name":"_totalDaemonizedErrors","internalType":"uint256"}],"name":"showDaemonizedErrors","inputs":[{"type":"uint256","name":"startIndex","internalType":"uint256"},{"type":"uint256","name":"numErrorTypesToShow","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_lastErrorBlock","internalType":"uint256[]"},{"type":"uint256[]","name":"_numErrors","internalType":"uint256[]"},{"type":"string[]","name":"_errorString","internalType":"string[]"},{"type":"address[]","name":"_erroringContract","internalType":"address[]"},{"type":"uint256","name":"_totalDaemonizedErrors","internalType":"uint256"}],"name":"showLastDaemonizedError","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"systemLastTriggeredAt","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalMintingReceivedWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalMintingRequestedWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalMintingWithdrawnWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSelfDestructReceivedWei","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_toMintWei","internalType":"uint256"}],"name":"trigger","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unregisterAll","inputs":[]}]
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101cf5760003560e01c80638be2fb8611610104578063d38bfff4116100a2578063e9de7d6011610071578063e9de7d6014610322578063ecdda0dd14610335578063ed21b6e414610348578063ee323c921461035f576101cf565b8063d38bfff4146102e9578063d48a38df146102fc578063dded1b4714610304578063e371aef01461030c576101cf565b8063a6817ace116100de578063a6817ace146102be578063be0522e0146102c6578063c373a08e146102ce578063c9f960eb146102e1576101cf565b80638be2fb861461029b5780638ccf77a0146102a35780639d6a890f146102ab576101cf565b806362da19a511610171578063689c49991161014b578063689c49991461026557806372993615146102785780637fec8d3814610280578063870196b814610288576101cf565b806362da19a51461023c578063639031431461024457806363d4a53a1461024c576101cf565b80635042916c116101ad5780635042916c146102025780635aa6e675146102175780635d36b1901461022c57806360f7ac9714610234576101cf565b806310663750146101d45780631d76dea1146101f25780634f6a77b5146101fa575b600080fd5b6101dc610372565b6040516101e991906127a1565b60405180910390f35b6101dc610378565b6101dc61037e565b61021561021036600461249c565b610384565b005b61021f6103da565b6040516101e99190612592565b6102156103e9565b61021f6104ab565b6101dc6104ba565b6101dc6104c0565b6102546104d0565b6040516101e9959493929190612698565b61021561027336600461240d565b61050b565b6101dc61083a565b6101dc610840565b61021561029636600461249c565b6108eb565b6101dc610a3b565b610215610a41565b6102156102b93660046123f1565b610a9c565b6101dc610aa1565b61021f610aa7565b6102156102dc3660046123f1565b610ab6565b61021f610b5b565b6102156102f73660046123f1565b610b9a565b6101dc610c5c565b6101dc610c62565b610314610c68565b6040516101e992919061277f565b61021561033036600461249c565b610c89565b6102546103433660046124b4565b610dc2565b61035061111f565b6040516101e993929190612623565b61021561036d3660046123f1565b6112e4565b60055481565b60095481565b60085481565b6000546001600160a01b031633146103d5576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600c55565b6000546001600160a01b031681565b6001546001600160a01b03163314610438576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd0818db185a5b585a5b9d609a1b604482015290519081900360640190fd5b600054600154604080516001600160a01b03938416815292909116602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031681565b60045481565b60006104ca6113fb565b90505b90565b600b546060908190819081906000906104fa90600160c01b90046001600160401b03166001610dc2565b945094509450945094509091929394565b6000546001600160a01b0316331461055c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b604080518082019091526008815267746f6f206d616e7960c01b60208201528190600a8211156105a85760405162461bcd60e51b815260040161059f919061276c565b60405180910390fd5b506105b1611406565b60005b818110156108345760008484838181106105ca57fe5b6105e092602060409092020190810191506123f1565b6001600160a01b031614156040518060400160405280600c81526020016b61646472657373207a65726f60a01b8152509061062e5760405162461bcd60e51b815260040161059f919061276c565b5060105460005b818110156106d7576010818154811061064a57fe5b6000918252602090912001546001600160a01b031686868581811061066b57fe5b61068192602060409092020190810191506123f1565b6001600160a01b031614156040518060400160405280600b81526020016a647570206164647265737360a81b815250906106ce5760405162461bcd60e51b815260040161059f919061276c565b50600101610635565b5060108585848181106106e657fe5b6106fc92602060409092020190810191506123f1565b81546001810183556000928352602090922090910180546001600160a01b0319166001600160a01b0390921691909117905584848381811061073a57fe5b905060400201602001356011600087878681811061075457fe5b61076a92602060409092020190810191506123f1565b6001600160a01b03166001600160a01b03168152602001908152602001600020819055506000601260008787868181106107a057fe5b6107b692602060409092020190810191506123f1565b6001600160a01b031681526020810191909152604001600020557f86d03f430c7616021073d7a71766f632f1ce19f289aa989534d9f4732253eb598585848181106107fd57fe5b61081392602060409092020190810191506123f1565b6001604051610823929190612737565b60405180910390a1506001016105b4565b50505050565b60075481565b6002546000906001600160a01b031661088557610885306040518060400160405280600e81526020016d696e666c6174696f6e207a65726f60901b81525060006114b6565b60026001609c1b01331461089857600080fd5b6108a061167a565b905060006108ac611ee5565b90504781146108e7576108e7306040518060400160405280600e81526020016d6f7574206f662062616c616e636560901b81525060006114b6565b5090565b6000546001600160a01b0316331461093c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60085461094c90606e6064611f0a565b811115604051806040016040528060118152602001700dac2f040dad2dce840e8dede40d0d2ced607b1b815250906109975760405162461bcd60e51b815260040161059f919061276c565b5060408051808201909152601081526f6d6178206d696e74206973207a65726f60801b6020820152816109dd5760405162461bcd60e51b815260040161059f919061276c565b5062015180600a54014211604051806040016040528060128152602001711d1a5b594819d85c081d1bdbc81cda1bdc9d60721b81525090610a315760405162461bcd60e51b815260040161059f919061276c565b5060085542600a55565b60035481565b6000546001600160a01b03163314610a92576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b610a9a611406565b565bfe5b50565b600a5481565b6002546001600160a01b031681565b6000546001600160a01b03163314610b07576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b699181900360200190a150565b600f5460009060ff16610b8857600f805460ff191660011790556000610b7f612012565b91506104cd9050565b506000546001600160a01b03166104cd565b6000546001600160a01b03163314610beb576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b600c5481565b60065481565b600b546001600160c01b03811690600160c01b90046001600160401b031682565b60025460408051808201909152600d81526c3737ba1034b7333630ba34b7b760991b602082015233916001600160a01b03168214610cda5760405162461bcd60e51b815260040161059f919061276c565b5060085482111560405180604001604052806007815260200166746f6f2062696760c81b81525090610d1f5760405162461bcd60e51b815260040161059f919061276c565b5042610d296113fb565b10604051806040016040528060098152602001683a37b79037b33a32b760b91b81525090610d6a5760405162461bcd60e51b815260040161059f919061276c565b508115610dbe5742600955600454610d829083612032565b6004556040517f4c4f1efc376f31abeb51b72c5f9ed81cf4016591312bb02337e58149dcfaaab490610db59084906127a1565b60405180910390a15b5050565b606080606080600060148054905087106040518060400160405280601081526020016f0e6e8c2e4e840d2dcc8caf040d0d2ced60831b81525090610e195760405162461bcd60e51b815260040161059f919061276c565b506014546000908888011115610e3457601454889003610e36565b865b9050806001600160401b0381118015610e4e57600080fd5b50604051908082528060200260200182016040528015610e78578160200160208202803683370190505b509550806001600160401b0381118015610e9157600080fd5b50604051908082528060200260200182016040528015610ebb578160200160208202803683370190505b509450806001600160401b0381118015610ed457600080fd5b50604051908082528060200260200182016040528015610f0857816020015b6060815260200190600190039081610ef35790505b509350806001600160401b0381118015610f2157600080fd5b50604051908082528060200260200182016040528015610f4b578160200160208202803683370190505b50925060005b818110156111035760006014828b0181548110610f6a57fe5b6000918252602080832090910154808352601390915260409091205489519192506001600160c01b031690899084908110610fa157fe5b6020026020010181815250506013600082815260200190815260200160002060000160189054906101000a90046001600160401b03166001600160401b0316878381518110610fec57fe5b6020908102919091018101919091526000828152601382526040908190206002908101805483516001821615610100026000190190911692909204601f810185900485028301850190935282825290929091908301828280156110905780601f1061106557610100808354040283529160200191611090565b820191906000526020600020905b81548152906001019060200180831161107357829003601f168201915b50505050508683815181106110a157fe5b60200260200101819052506013600082815260200190815260200160002060010160009054906101000a90046001600160a01b03168583815181106110e257fe5b6001600160a01b039092166020928302919091019091015250600101610f51565b5050600b549497939650919450926001600160c01b0316919050565b60105460609081908190806001600160401b038111801561113f57600080fd5b50604051908082528060200260200182016040528015611169578160200160208202803683370190505b509350806001600160401b038111801561118257600080fd5b506040519080825280602002602001820160405280156111ac578160200160208202803683370190505b509250806001600160401b03811180156111c557600080fd5b506040519080825280602002602001820160405280156111ef578160200160208202803683370190505b50915060005b818110156112dd5760006010828154811061120c57fe5b9060005260206000200160009054906101000a90046001600160a01b031690508086838151811061123957fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060116000826001600160a01b03166001600160a01b031681526020019081526020016000205485838151811061128b57fe5b60200260200101818152505060126000826001600160a01b03166001600160a01b03168152602001908152602001600020548483815181106112c957fe5b6020908102919091010152506001016111f5565b5050909192565b6000546001600160a01b03163314611335576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60408051808201909152600e81526d696e666c6174696f6e207a65726f60901b60208201526001600160a01b0382166113815760405162461bcd60e51b815260040161059f919061276c565b506002546040517f4bdd1012a7d55ed9afad8675a125e1b68c7c15f712c0f3d5cddac69c3b979805916113bf9184916001600160a01b031690612752565b60405180910390a1600280546001600160a01b0319166001600160a01b038316179055600854610a9e576a295be96e6406697200000060085550565b600954620143700190565b60105460005b81811015610dbe576010805460009190600019810190811061142a57fe5b600091825260209091200154601080546001600160a01b039092169250908061144f57fe5b600082815260208120820160001990810180546001600160a01b03191690559091019091556040517f86d03f430c7616021073d7a71766f632f1ce19f289aa989534d9f4732253eb59916114a591849190612737565b60405180910390a15060010161140c565b600083836040516020016114cb9291906125a6565b60408051808303601f190181529181528151602092830120600081815260139093529120805491925090600160c01b90046001600160401b03166115b25760148054600180820183556000929092527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec01839055810180546001600160a01b0319166001600160a01b038716179055611565846040612095565b805161157b916002840191602090910190612359565b5060145460018201805467ffffffffffffffff60a01b1916600160a01b6000199093016001600160401b0316929092029190911790555b8054436001600160c01b038181166001600160401b03600160c01b80860482166001019091160291909316176001600160c01b0319169190911782556040517f7a459ed083a9b267865360013a5ad6dbc07e5befe6e4f71671c940fdd4206bee9161162391889190889088906125eb565b60405180910390a1600b80546001600160c01b0319811660016001600160c01b0392831681018316919091178084559301549216600160a01b9092046001600160401b0316600160c01b0291909117905550505050565b600060035443141561168e575060006104cd565b43600355600d544790811115611a645760006116b7600e54600d5461203290919063ffffffff16565b90508082141561182c57600e546005546116d19082612032565b6005556040517fa42d823c276ad1990284418c303209194a75fa95a901f19752a9f65a407ffa8c906117049083906127a1565b60405180910390a1600260009054906101000a90046001600160a01b03166001600160a01b031663c611c2c5826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561175c57600080fd5b505af19350505050801561176e575060015b6117dd5761177a6127b0565b806117855750611797565b611791308260006114b6565b506117d8565b6117d8306040518060400160405280601d81526020017f756e6b6e6f776e206572726f722e20726563656976654d696e74696e6700000081525060006114b6565b611826565b6006546117ea9082612032565b6006556040517f12773bf711e11ec0b058c3856d441d726d2dc89113706c4f4175571f1e830c5a9061181d9083906127a1565b60405180910390a15b50611a62565b8082101561188e57600061184b600d548461214990919063ffffffff16565b60075490915061185b9082612032565b6007556040517f3fe36bcb00188390b2b40f1ab66c58f660aea67fe98b9f80667f692e1a9ab3689061181d9083906127a1565b600e5460055461189d91612032565b600555600e54600d546000916118be916118b8908690612149565b90612149565b6007549091506118ce9082612032565b600755600e546040517fa42d823c276ad1990284418c303209194a75fa95a901f19752a9f65a407ffa8c91611902916127a1565b60405180910390a17f3fe36bcb00188390b2b40f1ab66c58f660aea67fe98b9f80667f692e1a9ab3688160405161193991906127a1565b60405180910390a1600260009054906101000a90046001600160a01b03166001600160a01b031663c611c2c5600e546040518263ffffffff1660e01b81526004016000604051808303818588803b15801561199357600080fd5b505af1935050505080156119a5575060015b611a14576119b16127b0565b806119bc57506119ce565b6119c8308260006114b6565b50611a0f565b611a0f306040518060400160405280601d81526020017f756e6b6e6f776e206572726f722e20726563656976654d696e74696e6700000081525060006114b6565b611a60565b600e54600654611a2391612032565b600655600e546040517f12773bf711e11ec0b058c3856d441d726d2dc89113706c4f4175571f1e830c5a91611a57916127a1565b60405180910390a15b505b505b60105460005b81811015611e8357600060108281548110611a8157fe5b60009182526020808320909101546001600160a01b031680835260129091526040909120549091508015611b0d576001600160a01b0382166000908152601260205260409081902060001983019055517f9895eddb1e8569b1dae526135aa5cab97f982fdc3b0ff7e17920c95e3b9bda6290611b0090849084906125d2565b60405180910390a1611e79565b6001600160a01b038216600090815260116020526040812054905a90506204a768811015611b77577f9b5c4be38598cb8d8b6e07727d2303d1d9fc2dfc31ad323170f5ea4dcc1f914a858703604051611b6691906127a1565b60405180910390a150505050611e83565b620493df1981018215801590611b8c57508083105b15611b945750815b846001600160a01b0316636d0e8c34826040518263ffffffff1660e01b8152600401602060405180830381600088803b158015611bd057600080fd5b5087f193505050508015611c01575060408051601f3d908101601f19168201909252611bfe9181019061247c565b60015b611e3857611c0d6127b0565b80611c185750611c9f565b611c2586825a86036114b6565b856001600160a01b031663e22fdece6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611c6057600080fd5b505af1158015611c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c98919061247c565b5050611e33565b60005a9050600084118015611cbd575083611cba8483612149565b10155b15611d9057611cf1866040518060400160405280600a8152602001696f7574206f662067617360b01b8152508386036114b6565b6000866001600160a01b031663e22fdece6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611d2e57600080fd5b505af1158015611d42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d66919061247c565b905080611d8a57600c546001600160a01b0388166000908152601260205260409020555b50611e31565b611dbc86604051806040016040528060078152602001663ab735b737bbb760c91b8152508386036114b6565b856001600160a01b031663e22fdece6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611df757600080fd5b505af1158015611e0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2f919061247c565b505b505b611e75565b507fe7aa66356adbd5e839ef210626f6d8f6f72109c17fadf4c4f9ca82b315ae79b4855a8403604051611e6c9291906125d2565b60405180910390a15b5050505b5050600101611a6a565b50611e8c6121a6565b92508215611ed657600e8390556040517f34f843cef0df42035141347873da1758a6643358831b5ba5b1580be947644f9290611ec99085906127a1565b60405180910390a1611edc565b6000600e555b505047600d5590565b60006104ca600754611f0460065460055461214990919063ffffffff16565b90612032565b6000808211611f53576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b83611f605750600061200b565b83830283858281611f6d57fe5b041415611f8657828181611f7d57fe5b0491505061200b565b6000838681611f9157fe5b0490506000848781611f9f57fe5b0690506000858781611fad57fe5b0490506000868881611fbb57fe5b069050612003611fd588611fcf86856121bf565b90612218565b611f04611fe286866121bf565b611f04611fef89876121bf565b611f048d611ffd8c8b6121bf565b906121bf565b955050505050505b9392505050565b600073fffec6c83c8bf5c3f4ae0ccf8c45ce20e4560bd76104ca8161227f565b60008282018381101561208c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60606000839050828151116120ad578391505061208f565b6000836001600160401b03811180156120c557600080fd5b506040519080825280601f01601f1916602001820160405280156120f0576020820181803683370190505b50905060005b848110156121405782818151811061210a57fe5b602001015160f81c60f81b82828151811061212157fe5b60200101906001600160f81b031916908160001a9053506001016120f6565b50949350505050565b6000828211156121a0576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006104ca60055460045461214990919063ffffffff16565b6000826121ce5750600061208f565b828202828482816121db57fe5b041461208c5760405162461bcd60e51b815260040180806020018281038252602181526020018061286a6021913960400191505060405180910390fd5b600080821161226e576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161227757fe5b049392505050565b600154600160a01b900460ff16156122d5576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b828054600181600116156101000203166002900490600052602060002090601f01602090048101928261238f57600085556123d5565b82601f106123a857805160ff19168380011785556123d5565b828001600101855582156123d5579182015b828111156123d55782518255916020019190600101906123ba565b506108e79291505b808211156108e757600081556001016123dd565b600060208284031215612402578081fd5b813561208c81612854565b6000806020838503121561241f578081fd5b82356001600160401b0380821115612435578283fd5b818501915085601f830112612448578283fd5b813581811115612456578384fd5b86602060408302850101111561246a578384fd5b60209290920196919550909350505050565b60006020828403121561248d578081fd5b8151801515811461208c578182fd5b6000602082840312156124ad578081fd5b5035919050565b600080604083850312156124c6578182fd5b50508035926020909101359150565b6000815180845260208085019450808401835b8381101561250d5781516001600160a01b0316875295820195908201906001016124e8565b509495945050505050565b6000815180845260208085019450808401835b8381101561250d5781518752958201959082019060010161252b565b60008151808452815b8181101561256c57602081850181015186830182015201612550565b8181111561257d5782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03831681526040602082018190526000906125ca90830184612547565b949350505050565b6001600160a01b03929092168252602082015260400190565b600060018060a01b0386168252846020830152608060408301526126126080830185612547565b905082606083015295945050505050565b606080825284519082018190526000906020906080840190828801845b828110156126655781516001600160a01b031684529284019290840190600101612640565b505050838103828501526126798187612518565b915050828103604084015261268e8185612518565b9695505050505050565b600060a082526126ab60a0830188612518565b6020838203818501526126be8289612518565b848103604086015287518082529092508183019082810284018301838a01865b8381101561270c57601f198784030185526126fa838351612547565b948601949250908501906001016126de565b50508681036060880152612720818a6124d5565b955050505050508260808301529695505050505050565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392831681529116602082015260400190565b60006020825261200b6020830184612547565b6001600160c01b039290921682526001600160401b0316602082015260400190565b90815260200190565b60e01c90565b600060443d10156127c0576104cd565b600481823e6308c379a06127d482516127aa565b146127de576104cd565b6040513d600319016004823e80513d6001600160401b03816024840111818411171561280d57505050506104cd565b8284019250825191508082111561282757505050506104cd565b503d8301602082840101111561283f575050506104cd565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114610a9e57600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212204565821f65608e6e4fdb7076f78e5f829e603a82de85005cd73fca61d73e634f64736f6c63430007060033