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
- Verified at
- 2022-07-13T20:50:50.468475Z
./contracts/genesis/implementation/FlareDaemon.sol
// SPDX-License-Identifier: MIT // WARNING, WARNING, WARNING // If you modify this contract, you need to re-install the binary into the validator // genesis file for the chain you wish to run. See ./docs/CompilingContracts.md for more information. // You have been warned. That is all. pragma solidity 0.7.6; pragma abicoder v2; import "../../governance/implementation/GovernedAtGenesis.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../interface/IInflationGenesis.sol"; import "../interface/IFlareDaemonize.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; /** * @title Flare Daemon contract * @notice This contract exists to coordinate regular daemon-like polling of contracts * that are registered to receive said polling. The trigger method is called by the * validator right at the end of block state transition. */ contract FlareDaemon is GovernedAtGenesis, AddressUpdatable { using SafeMath for uint256; using SafePct for uint256; //==================================================================== // Data Structures //==================================================================== struct DaemonizedError { uint192 lastErrorBlock; uint64 numErrors; address fromContract; uint64 errorTypeIndex; string errorMessage; } struct LastErrorData { uint192 totalDaemonizedErrors; uint64 lastErrorTypeIndex; } struct Registration { IFlareDaemonize daemonizedContract; uint256 gasLimit; } string internal constant ERR_ALREADY_SET = "already set"; string internal constant ERR_OUT_OF_BALANCE = "out of balance"; string internal constant ERR_NOT_INFLATION = "not inflation"; string internal constant ERR_TOO_MANY = "too many"; string internal constant ERR_TOO_BIG = "too big"; string internal constant ERR_TOO_OFTEN = "too often"; string internal constant ERR_INFLATION_ZERO = "inflation zero"; string internal constant ERR_BLOCK_NUMBER_SMALL = "block.number small"; string internal constant INDEX_TOO_HIGH = "start index high"; string internal constant UPDATE_GAP_TOO_SHORT = "time gap too short"; string internal constant MAX_MINT_TOO_HIGH = "max mint too high"; string internal constant MAX_MINT_IS_ZERO = "max mint is zero"; string internal constant ERR_DUPLICATE_ADDRESS = "dup address"; string internal constant ERR_ADDRESS_ZERO = "address zero"; string internal constant ERR_OUT_OF_GAS = "out of gas"; string internal constant ERR_INFLATION_MINT_RECEIVE_FAIL = "unknown error. receiveMinting"; uint256 internal constant MAX_DAEMONIZE_CONTRACTS = 10; // Initial max mint request - 60 million native token uint256 internal constant MAX_MINTING_REQUEST_DEFAULT = 60000000 ether; // How often can inflation request minting from the validator - 23 hours constant uint256 internal constant MAX_MINTING_FREQUENCY_SEC = 23 hours; // How often can the maximal mint request amount be updated uint256 internal constant MAX_MINTING_REQUEST_FREQUENCY_SEC = 24 hours; // By how much can the maximum be increased (as a percentage of the previous maximum) uint256 internal constant MAX_MINTING_REQUEST_INCREASE_PERCENT = 110; // upper estimate of gas needed after error occurs in call to daemonizedContract.daemonize() uint256 internal constant MIN_GAS_LEFT_AFTER_DAEMONIZE = 300000; // lower estimate for gas needed for daemonize() call in trigger uint256 internal constant MIN_GAS_FOR_DAEMONIZE_CALL = 5000; IInflationGenesis public inflation; uint256 public systemLastTriggeredAt; uint256 public totalMintingRequestedWei; uint256 public totalMintingReceivedWei; uint256 public totalMintingWithdrawnWei; uint256 public totalSelfDestructReceivedWei; uint256 public maxMintingRequestWei; uint256 public lastMintRequestTs; uint256 public lastUpdateMaxMintRequestTs; LastErrorData public errorData; uint256 public blockHoldoff; uint256 private lastBalance; uint256 private expectedMintRequest; bool private initialized; // track deamonized contracts IFlareDaemonize[] internal daemonizeContracts; mapping (IFlareDaemonize => uint256) internal gasLimits; mapping (IFlareDaemonize => uint256) internal blockHoldoffsRemaining; // track daemonize errors mapping(bytes32 => DaemonizedError) internal daemonizedErrors; bytes32 [] internal daemonizeErrorHashes; event ContractDaemonized(address theContract, uint256 gasConsumed); event ContractDaemonizeErrored(address theContract, uint256 atBlock, string theMessage, uint256 gasConsumed); event ContractHeldOff(address theContract, uint256 blockHoldoffsRemaining); event ContractsSkippedOutOfGas(uint256 numberOfSkippedConstracts); event MintingRequestReceived(uint256 amountWei); event MintingRequestTriggered(uint256 amountWei); event MintingReceived(uint256 amountWei); event MintingWithdrawn(uint256 amountWei); event RegistrationUpdated(IFlareDaemonize theContract, bool add); event SelfDestructReceived(uint256 amountWei); event InflationSet(IInflationGenesis theNewContract, IInflationGenesis theOldContract); /** * @dev As there is not a constructor, this modifier exists to make sure the inflation * contract is set for methods that require it. */ modifier inflationSet { // Don't revert...just report. if (address(inflation) == address(0)) { addDaemonizeError(address(this), ERR_INFLATION_ZERO, 0); } _; } /** * @dev Access control to protect methods to allow only minters to call select methods * (like transferring balance out). */ modifier onlyInflation (address _inflation) { require (address(inflation) == _inflation, ERR_NOT_INFLATION); _; } /** * @dev Access control to protect trigger() method. * Please note that the sender address is the same as deployed FlareDaemon address in this case. */ modifier onlySystemTrigger { require (msg.sender == 0x1000000000000000000000000000000000000002); _; } //==================================================================== // Constructor for pre-compiled code //==================================================================== /** * @dev This constructor should contain no code as this contract is pre-loaded into the genesis block. * The super constructor is called for testing convenience. */ constructor() GovernedAtGenesis(address(0)) AddressUpdatable(address(0)) { /* empty block */ } //==================================================================== // Functions //==================================================================== /** * @notice Register contracts to be polled by the daemon process. * @param _registrations An array of Registration structures of IFlareDaemonize contracts to daemonize * and gas limits for each contract. * @dev A gas limit of zero will set no limit for the contract but the validator has an overall * limit for the trigger() method. * @dev If any registrations already exist, they will be unregistered. * @dev Contracts will be daemonized in the order in which presented via the _registrations array. */ function registerToDaemonize(Registration[] memory _registrations) external onlyGovernance { _registerToDaemonize(_registrations); } /** * @notice Queue up a minting request to send to the validator at next trigger. * @param _amountWei The amount to mint. */ function requestMinting(uint256 _amountWei) external onlyInflation(msg.sender) { require(_amountWei <= maxMintingRequestWei, ERR_TOO_BIG); require(_getNextMintRequestAllowedTs() < block.timestamp, ERR_TOO_OFTEN); if (_amountWei > 0) { lastMintRequestTs = block.timestamp; totalMintingRequestedWei = totalMintingRequestedWei.add(_amountWei); emit MintingRequestReceived(_amountWei); } } /** * @notice Set number of blocks that must elapse before a daemonized contract exceeding gas limit can have * its daemonize() method called again. * @param _blockHoldoff The number of blocks to holdoff. */ function setBlockHoldoff(uint256 _blockHoldoff) external onlyGovernance { blockHoldoff = _blockHoldoff; } /** * @notice Set limit on how much can be minted per request. * @param _maxMintingRequestWei The request maximum in wei. * @notice this number can't be udated too often */ function setMaxMintingRequest(uint256 _maxMintingRequestWei) external onlyGovernance { // make sure increase amount is reasonable require( _maxMintingRequestWei <= (maxMintingRequestWei.mulDiv(MAX_MINTING_REQUEST_INCREASE_PERCENT,100)), MAX_MINT_TOO_HIGH ); require(_maxMintingRequestWei > 0, MAX_MINT_IS_ZERO); // make sure enough time since last update require( block.timestamp > lastUpdateMaxMintRequestTs + MAX_MINTING_REQUEST_FREQUENCY_SEC, UPDATE_GAP_TOO_SHORT ); maxMintingRequestWei = _maxMintingRequestWei; lastUpdateMaxMintRequestTs = block.timestamp; } /** * @notice Sets the address udpater contract. * @param _addressUpdater The address updater contract. */ function setAddressUpdater(address _addressUpdater) external onlyGovernance { require(getAddressUpdater() == address(0), ERR_ALREADY_SET); setAddressUpdaterValue(_addressUpdater); } /** * @notice The meat of this contract. Poll all registered contracts, calling the daemonize() method of each, * in the order in which registered. * @return _toMintWei Return the amount to mint back to the validator. The asked for balance will show * up in the next block (it is actually added right before this block's state transition, * but well after this method call will see it.) * @dev This method watches for balances being added to this contract and handles appropriately - legit * mint requests as made via requestMinting, and also self-destruct sending to this contract, should * it happen for some reason. */ //slither-disable-next-line reentrancy-eth // method protected by reentrancy guard (see comment below) function trigger() external virtual inflationSet onlySystemTrigger returns (uint256 _toMintWei) { return triggerInternal(); } function getDaemonizedContractsData() external view returns( IFlareDaemonize[] memory _daemonizeContracts, uint256[] memory _gasLimits, uint256[] memory _blockHoldoffsRemaining ) { uint256 len = daemonizeContracts.length; _daemonizeContracts = new IFlareDaemonize[](len); _gasLimits = new uint256[](len); _blockHoldoffsRemaining = new uint256[](len); for (uint256 i; i < len; i++) { IFlareDaemonize daemonizeContract = daemonizeContracts[i]; _daemonizeContracts[i] = daemonizeContract; _gasLimits[i] = gasLimits[daemonizeContract]; _blockHoldoffsRemaining[i] = blockHoldoffsRemaining[daemonizeContract]; } } function getNextMintRequestAllowedTs() external view returns(uint256) { return _getNextMintRequestAllowedTs(); } function showLastDaemonizedError () external view returns( uint256[] memory _lastErrorBlock, uint256[] memory _numErrors, string[] memory _errorString, address[] memory _erroringContract, uint256 _totalDaemonizedErrors ) { return showDaemonizedErrors(errorData.lastErrorTypeIndex, 1); } /** * @notice Set the governance address to a hard-coded known address. * @dev This should be done at contract deployment time. * @return The governance address. */ function initialiseFixedAddress() public override returns(address) { if (!initialized) { initialized = true; address governanceAddress = super.initialiseFixedAddress(); return governanceAddress; } else { return governance(); } } function showDaemonizedErrors (uint startIndex, uint numErrorTypesToShow) public view returns( uint256[] memory _lastErrorBlock, uint256[] memory _numErrors, string[] memory _errorString, address[] memory _erroringContract, uint256 _totalDaemonizedErrors ) { require(startIndex < daemonizeErrorHashes.length, INDEX_TOO_HIGH); uint256 numReportElements = daemonizeErrorHashes.length >= startIndex + numErrorTypesToShow ? numErrorTypesToShow : daemonizeErrorHashes.length - startIndex; _lastErrorBlock = new uint256[] (numReportElements); _numErrors = new uint256[] (numReportElements); _errorString = new string[] (numReportElements); _erroringContract = new address[] (numReportElements); // we have error data error type. // error type is hash(error_string, source contract) // per error type we report how many times it happened. // what was last block it happened. // what is the error string. // what is the erroring contract for (uint i = 0; i < numReportElements; i++) { bytes32 hash = daemonizeErrorHashes[startIndex + i]; _lastErrorBlock[i] = daemonizedErrors[hash].lastErrorBlock; _numErrors[i] = daemonizedErrors[hash].numErrors; _errorString[i] = daemonizedErrors[hash].errorMessage; _erroringContract[i] = daemonizedErrors[hash].fromContract; } _totalDaemonizedErrors = errorData.totalDaemonizedErrors; } /** * @notice Implementation of the AddressUpdatable abstract method - updates Inflation and daemonized contracts. * @dev It also sets `maxMintingRequestWei` if it was not set before. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { IInflationGenesis _inflation = IInflationGenesis( _getContractAddress(_contractNameHashes, _contractAddresses, "Inflation")); emit InflationSet(_inflation, inflation); inflation = _inflation; if (maxMintingRequestWei == 0) { maxMintingRequestWei = MAX_MINTING_REQUEST_DEFAULT; } uint256 len = daemonizeContracts.length; if (len == 0) { return; } Registration[] memory registrations = new Registration[](len); for (uint256 i = 0; i < len; i++) { IFlareDaemonize daemonizeContract = daemonizeContracts[i]; registrations[i].daemonizedContract = IFlareDaemonize( _getContractAddress(_contractNameHashes, _contractAddresses, daemonizeContract.getContractName())); registrations[i].gasLimit = gasLimits[daemonizeContract]; } _registerToDaemonize(registrations); } /** * @notice Implementation of the trigger() method. The external wrapper has extra guard for msg.sender. */ //slither-disable-next-line reentrancy-eth // method protected by reentrancy guard (see comment below) function triggerInternal() internal returns (uint256 _toMintWei) { // only one trigger() call per block allowed // this also serves as reentrancy guard, since any re-entry will happen in the same block if(block.number == systemLastTriggeredAt) return 0; systemLastTriggeredAt = block.number; uint256 currentBalance = address(this).balance; // Did the validator or a self-destructor conjure some native token? if (currentBalance > lastBalance) { uint256 balanceExpected = lastBalance.add(expectedMintRequest); // Did we get what was last asked for? if (currentBalance == balanceExpected) { // Yes, so assume it all came from the validator. uint256 minted = expectedMintRequest; totalMintingReceivedWei = totalMintingReceivedWei.add(minted); emit MintingReceived(minted); //slither-disable-next-line arbitrary-send // only sent to inflation, set by governance try inflation.receiveMinting{ value: minted }() { totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(minted); emit MintingWithdrawn(minted); } catch Error(string memory message) { addDaemonizeError(address(this), message, 0); } catch { addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0); } } else if (currentBalance < balanceExpected) { // No, and if less, there are two possibilities: 1) the validator did not // send us what we asked (not possible unless a bug), or 2) an attacker // sent us something in between a request and a mint. Assume 2. uint256 selfDestructReceived = currentBalance.sub(lastBalance); totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived); emit SelfDestructReceived(selfDestructReceived); } else { // No, so assume we got a minting request (perhaps zero...does not matter) // and some self-destruct proceeds (unlikely but can happen). totalMintingReceivedWei = totalMintingReceivedWei.add(expectedMintRequest); uint256 selfDestructReceived = currentBalance.sub(lastBalance).sub(expectedMintRequest); totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived); emit MintingReceived(expectedMintRequest); emit SelfDestructReceived(selfDestructReceived); //slither-disable-next-line arbitrary-send // only sent to inflation, set by governance try inflation.receiveMinting{ value: expectedMintRequest }() { totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(expectedMintRequest); emit MintingWithdrawn(expectedMintRequest); } catch Error(string memory message) { addDaemonizeError(address(this), message, 0); } catch { addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0); } } } uint256 len = daemonizeContracts.length; // Perform trigger operations here for (uint256 i = 0; i < len; i++) { IFlareDaemonize daemonizedContract = daemonizeContracts[i]; uint256 blockHoldoffRemainingForContract = blockHoldoffsRemaining[daemonizedContract]; if (blockHoldoffRemainingForContract > 0) { blockHoldoffsRemaining[daemonizedContract] = blockHoldoffRemainingForContract - 1; emit ContractHeldOff(address(daemonizedContract), blockHoldoffRemainingForContract); } else { // Figure out what gas to limit call by uint256 gasLimit = gasLimits[daemonizedContract]; uint256 startGas = gasleft(); // End loop if there isn't enough gas left for any daemonize call if (startGas < MIN_GAS_LEFT_AFTER_DAEMONIZE + MIN_GAS_FOR_DAEMONIZE_CALL) { emit ContractsSkippedOutOfGas(len - i); break; } // Calculate the gas limit for the next call uint256 useGas = startGas - MIN_GAS_LEFT_AFTER_DAEMONIZE; if (gasLimit > 0 && gasLimit < useGas) { useGas = gasLimit; } // Run daemonize for the contract, consume errors, and record try daemonizedContract.daemonize{gas: useGas}() { emit ContractDaemonized(address(daemonizedContract), (startGas - gasleft())); // Catch all requires with messages } catch Error(string memory message) { addDaemonizeError(address(daemonizedContract), message, (startGas - gasleft())); daemonizedContract.switchToFallbackMode(); // Catch everything else...out of gas, div by zero, asserts, etc. } catch { uint256 endGas = gasleft(); // Interpret out of gas errors if (gasLimit > 0 && startGas.sub(endGas) >= gasLimit) { addDaemonizeError(address(daemonizedContract), ERR_OUT_OF_GAS, (startGas - endGas)); // When daemonize() fails with out-of-gas, try to fix it in two steps: // 1) try to switch contract to fallback mode // (to allow the contract's daemonize() to recover in fallback mode in next block) // 2) if constract is already in fallback mode or fallback mode is not supported // (switchToFallbackMode() returns false), start the holdoff for this contract bool switchedToFallback = daemonizedContract.switchToFallbackMode(); if (!switchedToFallback) { blockHoldoffsRemaining[daemonizedContract] = blockHoldoff; } } else { // Don't know error cause...just log it as unknown addDaemonizeError(address(daemonizedContract), "unknown", (startGas - endGas)); daemonizedContract.switchToFallbackMode(); } } } } // Get any requested minting and return to validator _toMintWei = getPendingMintRequest(); if (_toMintWei > 0) { expectedMintRequest = _toMintWei; emit MintingRequestTriggered(_toMintWei); } else { expectedMintRequest = 0; } // Update balance lastBalance = address(this).balance; // We should be in balance - don't revert, just report... uint256 contractBalanceExpected = getExpectedBalance(); if (contractBalanceExpected != address(this).balance) { addDaemonizeError(address(this), ERR_OUT_OF_BALANCE, 0); } } function addDaemonizeError(address daemonizedContract, string memory message, uint256 gasConsumed) internal { bytes32 errorStringHash = keccak256(abi.encode(daemonizedContract, message)); DaemonizedError storage daemonizedError = daemonizedErrors[errorStringHash]; if (daemonizedError.numErrors == 0) { // first time we recieve this error string. daemonizeErrorHashes.push(errorStringHash); daemonizedError.fromContract = daemonizedContract; // limit message length to fit in fixed number of storage words (to make gas usage predictable) daemonizedError.errorMessage = truncateString(message, 64); daemonizedError.errorTypeIndex = uint64(daemonizeErrorHashes.length - 1); } daemonizedError.numErrors += 1; daemonizedError.lastErrorBlock = uint192(block.number); emit ContractDaemonizeErrored(daemonizedContract, block.number, message, gasConsumed); errorData.totalDaemonizedErrors += 1; errorData.lastErrorTypeIndex = daemonizedError.errorTypeIndex; } /** * @notice Register contracts to be polled by the daemon process. * @param _registrations An array of Registration structures of IFlareDaemonize contracts to daemonize * and gas limits for each contract. * @dev A gas limit of zero will set no limit for the contract but the validator has an overall * limit for the trigger() method. * @dev If any registrations already exist, they will be unregistered. * @dev Contracts will be daemonized in the order in which presented via the _registrations array. */ function _registerToDaemonize(Registration[] memory _registrations) internal { // Make sure there are not too many contracts to register. uint256 registrationsLength = _registrations.length; require(registrationsLength <= MAX_DAEMONIZE_CONTRACTS, ERR_TOO_MANY); // Unregister everything first _unregisterAll(); // Loop over all contracts to register for (uint256 registrationIndex = 0; registrationIndex < registrationsLength; registrationIndex++) { // Address cannot be zero require(address(_registrations[registrationIndex].daemonizedContract) != address(0), ERR_ADDRESS_ZERO); uint256 daemonizeContractsLength = daemonizeContracts.length; // Make sure no dups...yes, inefficient. Registration should not be done often. for (uint256 i = 0; i < daemonizeContractsLength; i++) { require(_registrations[registrationIndex].daemonizedContract != daemonizeContracts[i], ERR_DUPLICATE_ADDRESS); // already registered } // Store off the registered contract to daemonize, in the order presented. daemonizeContracts.push(_registrations[registrationIndex].daemonizedContract); // Record the gas limit for the contract. gasLimits[_registrations[registrationIndex].daemonizedContract] = _registrations[registrationIndex].gasLimit; // Clear any blocks being held off for the given contract, if any. Contracts may be re-presented // if only order is being modified, for example. blockHoldoffsRemaining[_registrations[registrationIndex].daemonizedContract] = 0; emit RegistrationUpdated (_registrations[registrationIndex].daemonizedContract, true); } } /** * @notice Unregister all contracts from being polled by the daemon process. */ function _unregisterAll() private { uint256 len = daemonizeContracts.length; for (uint256 i = 0; i < len; i++) { IFlareDaemonize daemonizedContract = daemonizeContracts[daemonizeContracts.length - 1]; daemonizeContracts.pop(); emit RegistrationUpdated (daemonizedContract, false); } } /** * @notice Net totals to obtain the expected balance of the contract. */ function getExpectedBalance() private view returns(uint256 _balanceExpectedWei) { _balanceExpectedWei = totalMintingReceivedWei. sub(totalMintingWithdrawnWei). add(totalSelfDestructReceivedWei); } /** * @notice Net total received from total requested. */ function getPendingMintRequest() private view returns(uint256 _mintRequestPendingWei) { _mintRequestPendingWei = totalMintingRequestedWei.sub(totalMintingReceivedWei); } function _getNextMintRequestAllowedTs() internal view returns (uint256) { return (lastMintRequestTs + MAX_MINTING_FREQUENCY_SEC); } function truncateString(string memory _str, uint256 _maxlength) private pure returns (string memory) { bytes memory strbytes = bytes(_str); if (strbytes.length <= _maxlength) { return _str; } bytes memory result = new bytes(_maxlength); for (uint256 i = 0; i < _maxlength; i++) { result[i] = strbytes[i]; } return string(result); } }
./contracts/addressUpdater/implementation/AddressUpdatable.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../interface/IIAddressUpdatable.sol"; abstract contract AddressUpdatable is IIAddressUpdatable { // https://docs.soliditylang.org/en/v0.8.7/contracts.html#constant-and-immutable-state-variables // No storage slot is allocated bytes32 internal constant ADDRESS_STORAGE_POSITION = keccak256("flare.diamond.AddressUpdatable.ADDRESS_STORAGE_POSITION"); modifier onlyAddressUpdater() { require (msg.sender == getAddressUpdater(), "only address updater"); _; } constructor(address _addressUpdater) { setAddressUpdaterValue(_addressUpdater); } function getAddressUpdater() public view returns (address _addressUpdater) { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { _addressUpdater := sload(position) } } /** * @notice external method called from AddressUpdater only */ function updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) external override onlyAddressUpdater { // update addressUpdater address setAddressUpdaterValue(_getContractAddress(_contractNameHashes, _contractAddresses, "AddressUpdater")); // update all other addresses _updateContractAddresses(_contractNameHashes, _contractAddresses); } /** * @notice virtual method that a contract extending AddressUpdatable must implement */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal virtual; /** * @notice helper method to get contract address * @dev it reverts if contract name does not exist */ function _getContractAddress( bytes32[] memory _nameHashes, address[] memory _addresses, string memory _nameToFind ) internal pure returns(address) { bytes32 nameHash = keccak256(abi.encode(_nameToFind)); address a = address(0); for (uint256 i = 0; i < _nameHashes.length; i++) { if (nameHash == _nameHashes[i]) { a = _addresses[i]; break; } } require(a != address(0), "address zero"); return a; } function setAddressUpdaterValue(address _addressUpdater) internal { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { sstore(position, _addressUpdater) } } }
./contracts/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/interface/IFlareDaemonize.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; /// Any contracts that want to recieve a trigger from Flare daemon should /// implement IFlareDaemonize interface IFlareDaemonize { /// Implement this function for recieving a trigger from FlareDaemon. function daemonize() external returns (bool); /// This function will be called after an error is caught in daemonize(). /// It will switch the contract to a simpler fallback mode, which hopefully works when full mode doesn't. /// Not every contract needs to support fallback mode (FtsoManager does), so this method may be empty. /// Switching back to normal mode is left to the contract (typically a governed method call). /// This function may be called due to low-gas error, so it shouldn't use more than ~30.000 gas. /// @return true if switched to fallback mode, false if already in fallback mode or if falback not supported function switchToFallbackMode() external returns (bool); /// Implement this function for updating daemonized contracts through AddressUpdater. function getContractName() external view returns (string memory); }
./contracts/genesis/interface/IInflationGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IInflationGenesis { /** * @notice Receive newly minted native tokens from the FlareDaemon. * @dev Assume that the amount received will be >= last topup requested across all services. * If there is not enough balance sent to cover the topup request, expect library method will revert. * Also assume that any balance received greater than the topup request calculated * came from self-destructor sending a balance to this contract. */ function receiveMinting() external payable; }
./contracts/governance/implementation/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/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/SafePct.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; /** * @dev Compute percentages safely without phantom overflows. * * Intermediate operations can overflow even when the result will always * fit into computed type. Developers usually * assume that overflows raise errors. `SafePct` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafePct { using SafeMath for uint256; /** * Requirements: * * - intermediate operations must revert on overflow */ function mulDiv(uint256 x, uint256 y, uint256 z) internal pure returns (uint256) { require(z > 0, "Division by zero"); if (x == 0) return 0; uint256 xy = x * y; if (xy / x == y) { // no overflow happened - same as in SafeMath mul return xy / z; } //slither-disable-next-line divide-before-multiply uint256 a = x / z; uint256 b = x % z; // x = a * z + b //slither-disable-next-line divide-before-multiply uint256 c = y / z; uint256 d = y % z; // y = c * z + d return (a.mul(c).mul(z)).add(a.mul(d)).add(b.mul(c)).add(b.mul(d).div(z)); } }
@openzeppelin/contracts/math/SafeMath.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
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":"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":"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":"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":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"blockHoldoff","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint192","name":"totalDaemonizedErrors","internalType":"uint192"},{"type":"uint64","name":"lastErrorTypeIndex","internalType":"uint64"}],"name":"errorData","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_addressUpdater","internalType":"address"}],"name":"getAddressUpdater","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 IGovernanceSettings"}],"name":"governanceSettings","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":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"productionMode","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":"setAddressUpdater","inputs":[{"type":"address","name":"_addressUpdater","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBlockHoldoff","inputs":[{"type":"uint256","name":"_blockHoldoff","internalType":"uint256"}]},{"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":"nonpayable","outputs":[],"name":"switchToProductionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"systemLastTriggeredAt","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256"},{"type":"bytes","name":"encodedCall","internalType":"bytes"}],"name":"timelockedCalls","inputs":[{"type":"bytes4","name":"","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"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":[{"type":"uint256","name":"_toMintWei","internalType":"uint256"}],"name":"trigger","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateContractAddresses","inputs":[{"type":"bytes32[]","name":"_contractNameHashes","internalType":"bytes32[]"},{"type":"address[]","name":"_contractAddresses","internalType":"address[]"}]}]
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c8063870196b81161010f578063d48a38df116100a2578063e9de7d6011610071578063e9de7d6014610397578063ecdda0dd146103aa578063ed21b6e4146103bd578063f5a98383146103d4576101f0565b8063d48a38df1461035c578063dded1b4714610364578063e17f212e1461036c578063e371aef014610381576101f0565b8063aea36b53116100de578063aea36b5314610326578063b00c0b7614610339578063be0522e01461034c578063c9f960eb14610354576101f0565b8063870196b8146102f05780638be2fb86146103035780639d6a890f1461030b578063a6817ace1461031e576101f0565b806362da19a511610187578063689c499911610156578063689c4999146102ac57806372993615146102bf57806374e6310e146102c75780637fec8d38146102e8576101f0565b806362da19a514610270578063639031431461027857806363d4a53a1461028057806367fc402914610299576101f0565b80635267a15d116101c35780635267a15d146102385780635aa6e6751461024d5780635ff270791461025557806362354e0314610268576101f0565b806310663750146101f55780631d76dea1146102135780634f6a77b51461021b5780635042916c14610223575b600080fd5b6101fd6103dc565b60405161020a9190613397565b60405180910390f35b6101fd6103e2565b6101fd6103e8565b6102366102313660046130a6565b6103ee565b005b610240610435565b60405161020a919061317d565b61024061045a565b610236610263366004612ffe565b6104f0565b610240610845565b6101fd610850565b6101fd610856565b610288610860565b60405161020a959493929190613283565b6102366102a7366004612ffe565b61089b565b6102366102ba366004612f0e565b610983565b6101fd6109c0565b6102da6102d5366004612ffe565b6109c6565b60405161020a9291906133a0565b6101fd610a6c565b6102366102fe3660046130a6565b610acc565b6101fd610c08565b610236610319366004612e3c565b610c0e565b6101fd610c10565b610236610334366004612e3c565b610c16565b610236610347366004612e58565b610ca5565b610240610d50565b610240610d5f565b6101fd610d9b565b6101fd610da1565b610374610da7565b60405161020a9190613322565b610389610db7565b60405161020a929190613375565b6102366103a53660046130a6565b610dd8565b6102886103b83660046130be565b610f10565b6103c561126d565b60405161020a9392919061320e565b610236611432565b60055481565b60095481565b60085481565b600054600160b01b900460ff16806104105750600054600160a81b900460ff16155b156104275761041d6114ec565b600c819055610432565b610432600036611523565b50565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff1661047d576000546001600160a01b03166104ea565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b1580156104bd57600080fd5b505afa1580156104d1573d6000803e3d6000fd5b505050506040513d60208110156104e757600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561053457600080fd5b505afa158015610548573d6000803e3d6000fd5b505050506040513d602081101561055e57600080fd5b50516105a1576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b031981166000908152600160205260409020805461060d576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b8054421015610663576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106fd5780601f106106d2576101008083540402835291602001916106fd565b820191906000526020600020905b8154815290600101906020018083116106e057829003601f168201915b5050506001600160e01b03198616600090815260016020819052604082208281559495509092506107319150830182612ccb565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106107795780518252601f19909201916020918201910161075a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a161083f816116a6565b50505050565b60076001609c1b0181565b60045481565b60006104ea6116c3565b600b5460609081908190819060009061088a90600160c01b90046001600160401b03166001610f10565b945094509450945094509091929394565b6108a36116ce565b6001600160e01b0319811660009081526001602052604090205461090e576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b0319811660009081526001602081905260408220828155919061097e90830182612ccb565b505050565b600054600160b01b900460ff16806109a55750600054600160a81b900460ff16155b15610427576109b26114ec565b6109bb8161172d565b610432565b60075481565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f81018590048502860185019096528585529094919392909190830182828015610a625780601f10610a3757610100808354040283529160200191610a62565b820191906000526020600020905b815481529060010190602001808311610a4557829003601f168201915b5050505050905082565b6002546000906001600160a01b0316610ab157610ab1306040518060400160405280600e81526020016d696e666c6174696f6e207a65726f60901b81525060006119da565b60026001609c1b013314610ac457600080fd5b6104ea611b9e565b600054600160b01b900460ff1680610aee5750600054600160a81b900460ff16155b1561042757610afb6114ec565b600854610b0b90606e606461244f565b811115604051806040016040528060118152602001700dac2f040dad2dce840e8dede40d0d2ced607b1b81525090610b5f5760405162461bcd60e51b8152600401610b569190613362565b60405180910390fd5b5060408051808201909152601081526f6d6178206d696e74206973207a65726f60801b602082015281610ba55760405162461bcd60e51b8152600401610b569190613362565b5062015180600a54014211604051806040016040528060128152602001711d1a5b594819d85c081d1bdbc81cda1bdc9d60721b81525090610bf95760405162461bcd60e51b8152600401610b569190613362565b50600881905542600a55610432565b60035481565bfe5b600a5481565b600054600160b01b900460ff1680610c385750600054600160a81b900460ff16155b1561042757610c456114ec565b6000610c4f610435565b6001600160a01b0316146040518060400160405280600b81526020016a185b1c9958591e481cd95d60aa1b81525090610c9b5760405162461bcd60e51b8152600401610b569190613362565b506109bb8161255d565b610cad610435565b6001600160a01b0316336001600160a01b031614610d09576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b610d42610d3d83836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250612581565b61255d565b610d4c82826126ae565b5050565b6002546001600160a01b031681565b600f5460009060ff16610d8c57600f805460ff191660011790556000610d836128d6565b91506104ed9050565b610d9461045a565b90506104ed565b600c5481565b60065481565b600054600160a81b900460ff1681565b600b546001600160c01b03811690600160c01b90046001600160401b031682565b60025460408051808201909152600d81526c3737ba1034b7333630ba34b7b760991b602082015233916001600160a01b03168214610e295760405162461bcd60e51b8152600401610b569190613362565b5060085482111560405180604001604052806007815260200166746f6f2062696760c81b81525090610e6e5760405162461bcd60e51b8152600401610b569190613362565b5042610e786116c3565b10604051806040016040528060098152602001683a37b79037b33a32b760b91b81525090610eb95760405162461bcd60e51b8152600401610b569190613362565b508115610d4c5742600955600454610ed190836128f6565b6004556040517f4c4f1efc376f31abeb51b72c5f9ed81cf4016591312bb02337e58149dcfaaab490610f04908490613397565b60405180910390a15050565b606080606080600060148054905087106040518060400160405280601081526020016f0e6e8c2e4e840d2dcc8caf040d0d2ced60831b81525090610f675760405162461bcd60e51b8152600401610b569190613362565b506014546000908888011115610f8257601454889003610f84565b865b9050806001600160401b0381118015610f9c57600080fd5b50604051908082528060200260200182016040528015610fc6578160200160208202803683370190505b509550806001600160401b0381118015610fdf57600080fd5b50604051908082528060200260200182016040528015611009578160200160208202803683370190505b509450806001600160401b038111801561102257600080fd5b5060405190808252806020026020018201604052801561105657816020015b60608152602001906001900390816110415790505b509350806001600160401b038111801561106f57600080fd5b50604051908082528060200260200182016040528015611099578160200160208202803683370190505b50925060005b818110156112515760006014828b01815481106110b857fe5b6000918252602080832090910154808352601390915260409091205489519192506001600160c01b0316908990849081106110ef57fe5b6020026020010181815250506013600082815260200190815260200160002060000160189054906101000a90046001600160401b03166001600160401b031687838151811061113a57fe5b6020908102919091018101919091526000828152601382526040908190206002908101805483516001821615610100026000190190911692909204601f810185900485028301850190935282825290929091908301828280156111de5780601f106111b3576101008083540402835291602001916111de565b820191906000526020600020905b8154815290600101906020018083116111c157829003601f168201915b50505050508683815181106111ef57fe5b60200260200101819052506013600082815260200190815260200160002060010160009054906101000a90046001600160a01b031685838151811061123057fe5b6001600160a01b03909216602092830291909101909101525060010161109f565b5050600b549497939650919450926001600160c01b0316919050565b60105460609081908190806001600160401b038111801561128d57600080fd5b506040519080825280602002602001820160405280156112b7578160200160208202803683370190505b509350806001600160401b03811180156112d057600080fd5b506040519080825280602002602001820160405280156112fa578160200160208202803683370190505b509250806001600160401b038111801561131357600080fd5b5060405190808252806020026020018201604052801561133d578160200160208202803683370190505b50915060005b8181101561142b5760006010828154811061135a57fe5b9060005260206000200160009054906101000a90046001600160a01b031690508086838151811061138757fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060116000826001600160a01b03166001600160a01b03168152602001908152602001600020548583815181106113d957fe5b60200260200101818152505060126000826001600160a01b03166001600160a01b031681526020019081526020016000205484838151811061141757fe5b602090810291909101015250600101611343565b5050909192565b61143a6116ce565b600054600160a81b900460ff1615611499576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b600054600160b01b900460ff16156115195733301461150757fe5b6000805460ff60b01b19169055611521565b6115216116ce565b565b61152b6116ce565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561157357600080fd5b505afa158015611587573d6000803e3d6000fd5b505050506040513d602081101561159d57600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b0319861681526001602081815260409092208451815584830151805191945061162193928501920190612d0f565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b3d604051818101604052816000823e82156116bf578181f35b8181fd5b600954620143700190565b6116d661045a565b6001600160a01b0316336001600160a01b031614611521576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b8051604080518082019091526008815267746f6f206d616e7960c01b6020820152600a8211156117705760405162461bcd60e51b8152600401610b569190613362565b50611779612959565b60005b8181101561097e5760006001600160a01b031683828151811061179b57fe5b6020026020010151600001516001600160a01b031614156040518060400160405280600c81526020016b61646472657373207a65726f60a01b815250906117f55760405162461bcd60e51b8152600401610b569190613362565b5060105460005b81811015611899576010818154811061181157fe5b60009182526020909120015485516001600160a01b039091169086908590811061183757fe5b6020026020010151600001516001600160a01b031614156040518060400160405280600b81526020016a647570206164647265737360a81b815250906118905760405162461bcd60e51b8152600401610b569190613362565b506001016117fc565b5060108483815181106118a857fe5b6020908102919091018101515182546001810184556000938452919092200180546001600160a01b0319166001600160a01b0390921691909117905583518490839081106118f257fe5b6020026020010151602001516011600086858151811061190e57fe5b6020026020010151600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555060006012600086858151811061195057fe5b6020026020010151600001516001600160a01b03166001600160a01b03168152602001908152602001600020819055507f86d03f430c7616021073d7a71766f632f1ce19f289aa989534d9f4732253eb598483815181106119ad57fe5b60200260200101516000015160016040516119c992919061332d565b60405180910390a15060010161177c565b600083836040516020016119ef929190613191565b60408051808303601f190181529181528151602092830120600081815260139093529120805491925090600160c01b90046001600160401b0316611ad65760148054600180820183556000929092527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec01839055810180546001600160a01b0319166001600160a01b038716179055611a89846040612a09565b8051611a9f916002840191602090910190612d0f565b5060145460018201805467ffffffffffffffff60a01b1916600160a01b6000199093016001600160401b0316929092029190911790555b8054436001600160c01b038181166001600160401b03600160c01b80860482166001019091160291909316176001600160c01b0319169190911782556040517f7a459ed083a9b267865360013a5ad6dbc07e5befe6e4f71671c940fdd4206bee91611b4791889190889088906131d6565b60405180910390a1600b80546001600160c01b0319811660016001600160c01b0392831681018316919091178084559301549216600160a01b9092046001600160401b0316600160c01b0291909117905550505050565b6000600354431415611bb2575060006104ed565b43600355600d544790811115611f88576000611bdb600e54600d546128f690919063ffffffff16565b905080821415611d5057600e54600554611bf590826128f6565b6005556040517fa42d823c276ad1990284418c303209194a75fa95a901f19752a9f65a407ffa8c90611c28908390613397565b60405180910390a1600260009054906101000a90046001600160a01b03166001600160a01b031663c611c2c5826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611c8057600080fd5b505af193505050508015611c92575060015b611d0157611c9e61342b565b80611ca95750611cbb565b611cb5308260006119da565b50611cfc565b611cfc306040518060400160405280601d81526020017f756e6b6e6f776e206572726f722e20726563656976654d696e74696e6700000081525060006119da565b611d4a565b600654611d0e90826128f6565b6006556040517f12773bf711e11ec0b058c3856d441d726d2dc89113706c4f4175571f1e830c5a90611d41908390613397565b60405180910390a15b50611f86565b80821015611db2576000611d6f600d5484612abd90919063ffffffff16565b600754909150611d7f90826128f6565b6007556040517f3fe36bcb00188390b2b40f1ab66c58f660aea67fe98b9f80667f692e1a9ab36890611d41908390613397565b600e54600554611dc1916128f6565b600555600e54600d54600091611de291611ddc908690612abd565b90612abd565b600754909150611df290826128f6565b600755600e546040517fa42d823c276ad1990284418c303209194a75fa95a901f19752a9f65a407ffa8c91611e2691613397565b60405180910390a17f3fe36bcb00188390b2b40f1ab66c58f660aea67fe98b9f80667f692e1a9ab36881604051611e5d9190613397565b60405180910390a1600260009054906101000a90046001600160a01b03166001600160a01b031663c611c2c5600e546040518263ffffffff1660e01b81526004016000604051808303818588803b158015611eb757600080fd5b505af193505050508015611ec9575060015b611f3857611ed561342b565b80611ee05750611ef2565b611eec308260006119da565b50611f33565b611f33306040518060400160405280601d81526020017f756e6b6e6f776e206572726f722e20726563656976654d696e74696e6700000081525060006119da565b611f84565b600e54600654611f47916128f6565b600655600e546040517f12773bf711e11ec0b058c3856d441d726d2dc89113706c4f4175571f1e830c5a91611f7b91613397565b60405180910390a15b505b505b60105460005b818110156123a757600060108281548110611fa557fe5b60009182526020808320909101546001600160a01b031680835260129091526040909120549091508015612031576001600160a01b0382166000908152601260205260409081902060001983019055517f9895eddb1e8569b1dae526135aa5cab97f982fdc3b0ff7e17920c95e3b9bda629061202490849084906131bd565b60405180910390a161239d565b6001600160a01b038216600090815260116020526040812054905a90506204a76881101561209b577f9b5c4be38598cb8d8b6e07727d2303d1d9fc2dfc31ad323170f5ea4dcc1f914a85870360405161208a9190613397565b60405180910390a1505050506123a7565b620493df19810182158015906120b057508083105b156120b85750815b846001600160a01b0316636d0e8c34826040518263ffffffff1660e01b8152600401602060405180830381600088803b1580156120f457600080fd5b5087f193505050508015612125575060408051601f3d908101601f1916820190925261212291810190612fde565b60015b61235c5761213161342b565b8061213c57506121c3565b61214986825a86036119da565b856001600160a01b031663e22fdece6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561218457600080fd5b505af1158015612198573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121bc9190612fde565b5050612357565b60005a90506000841180156121e15750836121de8483612abd565b10155b156122b457612215866040518060400160405280600a8152602001696f7574206f662067617360b01b8152508386036119da565b6000866001600160a01b031663e22fdece6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561225257600080fd5b505af1158015612266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228a9190612fde565b9050806122ae57600c546001600160a01b0388166000908152601260205260409020555b50612355565b6122e086604051806040016040528060078152602001663ab735b737bbb760c91b8152508386036119da565b856001600160a01b031663e22fdece6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561231b57600080fd5b505af115801561232f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123539190612fde565b505b505b612399565b507fe7aa66356adbd5e839ef210626f6d8f6f72109c17fadf4c4f9ca82b315ae79b4855a84036040516123909291906131bd565b60405180910390a15b5050505b5050600101611f8e565b506123b0612b1a565b925082156123fa57600e8390556040517f34f843cef0df42035141347873da1758a6643358831b5ba5b1580be947644f92906123ed908590613397565b60405180910390a1612400565b6000600e555b47600d55600061240e612b33565b905047811461244957612449306040518060400160405280600e81526020016d6f7574206f662062616c616e636560901b81525060006119da565b50505090565b6000808211612498576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b836124a557506000612556565b838302838582816124b257fe5b0414156124cb578281816124c257fe5b04915050612556565b60008386816124d657fe5b04905060008487816124e457fe5b06905060008587816124f257fe5b049050600086888161250057fe5b06905061254e61251a886125148685612b52565b90612bab565b6125486125278686612b52565b6125486125348987612b52565b6125488d6125428c8b612b52565b90612b52565b906128f6565b955050505050505b9392505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b838110156125c55781810151838201526020016125ad565b50505050905090810190601f1680156125f25780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b865181101561265a5786818151811061262857fe5b60200260200101518314156126525785818151811061264357fe5b6020026020010151915061265a565b600101612613565b506001600160a01b0381166126a5576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b60006126dc83836040518060400160405280600981526020016824b7333630ba34b7b760b91b815250612581565b6002546040519192507f4bdd1012a7d55ed9afad8675a125e1b68c7c15f712c0f3d5cddac69c3b9798059161271e9184916001600160a01b0390911690613348565b60405180910390a1600280546001600160a01b0319166001600160a01b038316179055600854612758576a31a17e847807b1bc0000006008555b60105480612767575050610d4c565b6000816001600160401b038111801561277f57600080fd5b506040519080825280602002602001820160405280156127b957816020015b6127a6612d9b565b81526020019060019003908161279e5790505b50905060005b828110156128c5576000601082815481106127d657fe5b600091825260208220015460408051637afadd3960e11b815290516001600160a01b039092169350612869928a928a92869263f5f5ba7292600480840193829003018186803b15801561282857600080fd5b505afa15801561283c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128649190810190613026565b612581565b83838151811061287557fe5b6020908102919091018101516001600160a01b03928316905290821660009081526011909152604090205483518490849081106128ae57fe5b6020908102919091018101510152506001016127bf565b506128cf8161172d565b5050505050565b600073fffec6c83c8bf5c3f4ae0ccf8c45ce20e4560bd76104ea81612c12565b600082820183811015612950576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60105460005b81811015610d4c576010805460009190600019810190811061297d57fe5b600091825260209091200154601080546001600160a01b03909216925090806129a257fe5b600082815260208120820160001990810180546001600160a01b03191690559091019091556040517f86d03f430c7616021073d7a71766f632f1ce19f289aa989534d9f4732253eb59916129f89184919061332d565b60405180910390a15060010161295f565b6060600083905082815111612a215783915050612953565b6000836001600160401b0381118015612a3957600080fd5b506040519080825280601f01601f191660200182016040528015612a64576020820181803683370190505b50905060005b84811015612ab457828181518110612a7e57fe5b602001015160f81c60f81b828281518110612a9557fe5b60200101906001600160f81b031916908160001a905350600101612a6a565b50949350505050565b600082821115612b14576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006104ea600554600454612abd90919063ffffffff16565b60006104ea600754612548600654600554612abd90919063ffffffff16565b600082612b6157506000612953565b82820282848281612b6e57fe5b04146129505760405162461bcd60e51b81526004018080602001828103825260218152602001806134e56021913960400191505060405180910390fd5b6000808211612c01576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381612c0a57fe5b049392505050565b600054600160a01b900460ff1615612c68576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b50805460018160011615610100020316600290046000825580601f10612cf15750610432565b601f0160209004906000526020600020908101906104329190612db2565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612d455760008555612d8b565b82601f10612d5e57805160ff1916838001178555612d8b565b82800160010185558215612d8b579182015b82811115612d8b578251825591602001919060010190612d70565b50612d97929150612db2565b5090565b604080518082019091526000808252602082015290565b5b80821115612d975760008155600101612db3565b600082601f830112612dd7578081fd5b81356020612dec612de7836133dc565b6133b9565b8281528181019085830183850287018401881015612e08578586fd5b855b85811015612e2f578135612e1d816134cf565b84529284019290840190600101612e0a565b5090979650505050505050565b600060208284031215612e4d578081fd5b8135612950816134cf565b60008060408385031215612e6a578081fd5b82356001600160401b0380821115612e80578283fd5b818501915085601f830112612e93578283fd5b81356020612ea3612de7836133dc565b82815281810190858301838502870184018b1015612ebf578788fd5b8796505b84871015612ee1578035835260019690960195918301918301612ec3565b5096505086013592505080821115612ef7578283fd5b50612f0485828601612dc7565b9150509250929050565b60006020808385031215612f20578182fd5b82356001600160401b0380821115612f36578384fd5b818501915085601f830112612f49578384fd5b8135612f57612de7826133dc565b818152848101908486016040808502870188018b1015612f75578889fd5b8896505b84871015612fcf5780828c031215612f8f578889fd5b80518181018181108882111715612fa257fe5b82528235612faf816134cf565b815282890135898201528452600196909601959287019290810190612f79565b50909998505050505050505050565b600060208284031215612fef578081fd5b81518015158114612950578182fd5b60006020828403121561300f578081fd5b81356001600160e01b031981168114612950578182fd5b600060208284031215613037578081fd5b81516001600160401b038082111561304d578283fd5b818401915084601f830112613060578283fd5b81518181111561306c57fe5b61307f601f8201601f19166020016133b9565b9150808252856020828501011115613095578384fd5b612ab48160208401602086016133f9565b6000602082840312156130b7578081fd5b5035919050565b600080604083850312156130d0578182fd5b50508035926020909101359150565b6000815180845260208085019450808401835b838110156131175781516001600160a01b0316875295820195908201906001016130f2565b509495945050505050565b6000815180845260208085019450808401835b8381101561311757815187529582019590820190600101613135565b600081518084526131698160208601602086016133f9565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03831681526040602082018190526000906131b590830184613151565b949350505050565b6001600160a01b03929092168252602082015260400190565b600060018060a01b0386168252846020830152608060408301526131fd6080830185613151565b905082606083015295945050505050565b606080825284519082018190526000906020906080840190828801845b828110156132505781516001600160a01b03168452928401929084019060010161322b565b505050838103828501526132648187613122565b91505082810360408401526132798185613122565b9695505050505050565b600060a0825261329660a0830188613122565b6020838203818501526132a98289613122565b848103604086015287518082529092508183019082810284018301838a01865b838110156132f757601f198784030185526132e5838351613151565b948601949250908501906001016132c9565b5050868103606088015261330b818a6130df565b955050505050508260808301529695505050505050565b901515815260200190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6000602082526125566020830184613151565b6001600160c01b039290921682526001600160401b0316602082015260400190565b90815260200190565b6000838252604060208301526131b56040830184613151565b6040518181016001600160401b03811182821017156133d457fe5b604052919050565b60006001600160401b038211156133ef57fe5b5060209081020190565b60005b838110156134145781810151838201526020016133fc565b8381111561083f5750506000910152565b60e01c90565b600060443d101561343b576104ed565b600481823e6308c379a061344f8251613425565b14613459576104ed565b6040513d600319016004823e80513d6001600160401b03816024840111818411171561348857505050506104ed565b828401925082519150808211156134a257505050506104ed565b503d830160208284010111156134ba575050506104ed565b601f01601f1916810160200160405291505090565b6001600160a01b038116811461043257600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122024c81cc382b52201889f886cbc353194ac8eb254f5c2d35cb70533439e54edc564736f6c63430007060033