Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- FtsoManager
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- Verified at
- 2022-07-13T21:18:39.119580Z
Constructor Arguments
0000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b000000000000000000000000100000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000062cf1e4600000000000000000000000000000000000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000062d9a2300000000000000000000000000000000000000000000000000000000000049d400000000000000000000000000000000000000000000000000000000000000002
Arg [0] (address) : 0x4598a6c05910ab914f0cbaaca1911cd337d10d29
Arg [1] (address) : 0x1000000000000000000000000000000000000002
Arg [2] (address) : 0xbaf89d873d198ff78e72d2745b01cba3c6e5be6b
Arg [3] (address) : 0x1000000000000000000000000000000000000003
Arg [4] (address) : 0x0000000000000000000000000000000000000000
Arg [5] (uint256) : 1657740870
Arg [6] (uint256) : 180
Arg [7] (uint256) : 90
Arg [8] (uint256) : 1658430000
Arg [9] (uint256) : 302400
Arg [10] (uint256) : 2
contracts/ftso/implementation/FtsoManager.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../interface/IIFtsoManager.sol"; import "../interface/IIFtsoManagerV1.sol"; import "../interface/IIFtso.sol"; import "../lib/FtsoManagerSettings.sol"; import "../lib/FtsoManagement.sol"; import "../../genesis/implementation/FlareDaemon.sol"; import "../../genesis/interface/IIPriceSubmitter.sol"; import "../../governance/implementation/Governed.sol"; import "../../inflation/interface/IISupply.sol"; import "../../tokenPools/interface/IIFtsoRewardManager.sol"; import "../../token/implementation/CleanupBlockNumberManager.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../../utils/implementation/GovernedAndFlareDaemonized.sol"; import "../../utils/implementation/RevertErrorTracking.sol"; import "../../utils/interface/IIFtsoRegistry.sol"; import "../../utils/interface/IIVoterWhitelister.sol"; import "../../utils/interface/IUpdateValidators.sol"; /** * FtsoManager is in charge of: * - defining reward epochs (few days) * - per reward epoch choose a single block that represents vote power of this epoch. * - keep track of all FTSO contracts * - per price epoch (few minutes) * - randomly choose one FTSO for rewarding. * - trigger finalize price reveal epoch * - determines addresses and reward weights and triggers rewardDistribution */ //solhint-disable-next-line max-states-count contract FtsoManager is IIFtsoManager, GovernedAndFlareDaemonized, AddressUpdatable, RevertErrorTracking { using FtsoManagerSettings for FtsoManagerSettings.State; using FtsoManagement for FtsoManagement.State; uint256 public constant MAX_TRUSTED_ADDRESSES_LENGTH = 5; string internal constant ERR_FIRST_EPOCH_START_TS_IN_FUTURE = "First epoch start ts in future"; string internal constant ERR_REWARD_EPOCH_DURATION_ZERO = "Reward epoch 0"; string internal constant ERR_REWARD_EPOCH_START_TOO_SOON = "Reward epoch start too soon"; string internal constant ERR_REWARD_EPOCH_NOT_INITIALIZED = "Reward epoch not initialized yet"; string internal constant ERR_REWARD_EPOCH_START_CONDITION_INVALID = "Reward epoch start condition invalid"; string internal constant ERR_REWARD_EPOCH_DURATION_CONDITION_INVALID = "Reward epoch duration condition invalid"; string internal constant ERR_PRICE_EPOCH_DURATION_ZERO = "Price epoch 0"; string internal constant ERR_VOTE_POWER_INTERVAL_FRACTION_ZERO = "Vote power interval fraction 0"; string internal constant ERR_REVEAL_PRICE_EPOCH_DURATION_ZERO = "Reveal price epoch 0"; string internal constant ERR_REVEAL_PRICE_EPOCH_TOO_LONG = "Reveal price epoch too long"; string internal constant ERR_GOV_PARAMS_NOT_INIT_FOR_FTSOS = "Gov. params not initialized"; string internal constant ERR_GOV_PARAMS_INVALID = "Gov. params invalid"; string internal constant ERR_NOT_FOUND = "Not found"; string internal constant ERR_ALREADY_ADDED = "Already added"; string internal constant ERR_ALREADY_ACTIVATED = "Already activated"; string internal constant ERR_CLOSING_EXPIRED_REWARD_EPOCH_FAIL = "err close expired"; string internal constant ERR_SET_CLEANUP_BLOCK_FAIL = "err set cleanup block"; string internal constant ERR_PRICE_EPOCH_FINALIZE_FAIL = "err finalize price epoch"; string internal constant ERR_DISTRIBUTE_REWARD_FAIL = "err distribute rewards"; string internal constant ERR_ACCRUE_UNEARNED_REWARD_FAIL = "err accrue unearned rewards"; string internal constant ERR_FALLBACK_FINALIZE_FAIL = "err fallback finalize price epoch"; string internal constant ERR_INIT_EPOCH_REVEAL_FAIL = "err init epoch for reveal"; string internal constant ERR_FALLBACK_INIT_EPOCH_REVEAL_FAIL = "err fallback init epoch for reveal"; string internal constant ERR_UPDATE_REWARD_EPOCH_SWITCHOVER_CALL = "err calling updateActiveValidators"; bool public override active; mapping(uint256 => RewardEpochData) internal rewardEpochsMapping; address public lastRewardedFtsoAddress; uint256 internal rewardEpochsLength; uint256 public override currentRewardEpochEnds; FtsoManagerSettings.State public settings; FtsoManagement.State public ftsoManagement; // price epoch data uint256 internal immutable firstPriceEpochStartTs; uint256 internal immutable priceEpochDurationSeconds; uint256 internal immutable revealEpochDurationSeconds; uint256 internal lastUnprocessedPriceEpoch; uint256 internal lastUnprocessedPriceEpochRevealEnds; // indicates if lastUnprocessedPriceEpoch is initialized for reveal // it has to be finalized before new reward epoch can start bool internal lastUnprocessedPriceEpochInitialized; // reward Epoch data uint256 public immutable override rewardEpochsStartTs; uint256 public override rewardEpochDurationSeconds; uint256 internal votePowerIntervalFraction; uint256 internal nextRewardEpochToExpire; IIPriceSubmitter public immutable priceSubmitter; IIFtsoRewardManager public rewardManager; IISupply public supply; CleanupBlockNumberManager public cleanupBlockNumberManager; IUpdateValidators public updateOnRewardEpochSwitchover; // fallback mode bool internal fallbackMode; // all ftsos in fallback mode // for redeploy IIFtsoManagerV1 public immutable oldFtsoManager; constructor( address _governance, FlareDaemon _flareDaemon, address _addressUpdater, IIPriceSubmitter _priceSubmitter, IIFtsoManagerV1 _oldFtsoManager, uint256 _firstPriceEpochStartTs, uint256 _priceEpochDurationSeconds, uint256 _revealEpochDurationSeconds, uint256 _firstRewardEpochStartTs, uint256 _rewardEpochDurationSeconds, uint256 _votePowerIntervalFraction ) GovernedAndFlareDaemonized(_governance, _flareDaemon) AddressUpdatable(_addressUpdater) { require(block.timestamp >= _firstPriceEpochStartTs, ERR_FIRST_EPOCH_START_TS_IN_FUTURE); require(_rewardEpochDurationSeconds > 0, ERR_REWARD_EPOCH_DURATION_ZERO); require(_priceEpochDurationSeconds > 0, ERR_PRICE_EPOCH_DURATION_ZERO); require(_revealEpochDurationSeconds > 0, ERR_REVEAL_PRICE_EPOCH_DURATION_ZERO); require(_votePowerIntervalFraction > 0, ERR_VOTE_POWER_INTERVAL_FRACTION_ZERO); require(_revealEpochDurationSeconds < _priceEpochDurationSeconds, ERR_REVEAL_PRICE_EPOCH_TOO_LONG); require(_firstPriceEpochStartTs + _revealEpochDurationSeconds <= _firstRewardEpochStartTs, ERR_REWARD_EPOCH_START_TOO_SOON); require((_firstRewardEpochStartTs - _revealEpochDurationSeconds - _firstPriceEpochStartTs) % _priceEpochDurationSeconds == 0, ERR_REWARD_EPOCH_START_CONDITION_INVALID); require(_rewardEpochDurationSeconds % _priceEpochDurationSeconds == 0, ERR_REWARD_EPOCH_DURATION_CONDITION_INVALID); // reward epoch rewardEpochsStartTs = _firstRewardEpochStartTs; rewardEpochDurationSeconds = _rewardEpochDurationSeconds; votePowerIntervalFraction = _votePowerIntervalFraction; // price epoch firstPriceEpochStartTs = _firstPriceEpochStartTs; priceEpochDurationSeconds = _priceEpochDurationSeconds; revealEpochDurationSeconds = _revealEpochDurationSeconds; lastUnprocessedPriceEpochRevealEnds = _firstRewardEpochStartTs; lastUnprocessedPriceEpoch = (_firstRewardEpochStartTs - _firstPriceEpochStartTs) / _priceEpochDurationSeconds; priceSubmitter = _priceSubmitter; oldFtsoManager = _oldFtsoManager; } /** * @notice Set reward data to values from old ftso manager * @dev Can be called only before activation */ function setInitialRewardData( uint256 _nextRewardEpochToExpire, uint256 _rewardEpochsLength, uint256 _currentRewardEpochEnds ) external override onlyGovernance { require(!active, ERR_ALREADY_ACTIVATED); nextRewardEpochToExpire = _nextRewardEpochToExpire; rewardEpochsLength = _rewardEpochsLength; currentRewardEpochEnds = _currentRewardEpochEnds; } /** * @notice Activates FTSO manager (daemonize() runs jobs) */ function activate() external override onlyGovernance { active = true; } /** * @notice Runs task triggered by Daemon. * The tasks include the following by priority * - finalizePriceEpoch * - Set governance parameters and initialize epochs * - finalizeRewardEpoch */ function daemonize() external override onlyFlareDaemon returns (bool) { // flare daemon trigger. once every block if (!active) return false; if (rewardEpochsLength == 0) { _initializeFirstRewardEpoch(); } else { // all three conditions can be executed in the same block, // but are split into three `if else if` groups to reduce gas usage per one block if (lastUnprocessedPriceEpochInitialized && lastUnprocessedPriceEpochRevealEnds <= block.timestamp) { // finalizes initialized price epoch if reveal period is over // sets lastUnprocessedPriceEpochInitialized = false _finalizePriceEpoch(); } else if (!lastUnprocessedPriceEpochInitialized && currentRewardEpochEnds <= block.timestamp) { // initialized price epoch must be finalized before new reward epoch can start // advance currentRewardEpochEnds _finalizeRewardEpoch(); _closeExpiredRewardEpochs(); _cleanupOnRewardEpochFinalization(); _rewardEpochSwitchoverTrigger(); } else if (lastUnprocessedPriceEpochRevealEnds <= block.timestamp) { // new price epoch can be initialized after previous was finalized // and after new reward epoch was started (if needed) // initializes price epoch and sets governance parameters on ftsos and price submitter // advance lastUnprocessedPriceEpochRevealEnds, sets lastUnprocessedPriceEpochInitialized = true _initializeCurrentEpochFTSOStatesForReveal(); } } return true; } /** * @notice Called if out of gas or any other unknown error occures in flare daemonize call */ function switchToFallbackMode() external override onlyFlareDaemon returns (bool) { if (!fallbackMode) { fallbackMode = true; emit FallbackMode(true); return true; } return false; } /** * @notice Adds FTSO to the list of rewarded FTSOs * All ftsos in multi asset ftso must be managed by this ftso manager */ function addFtso(IIFtso _ftso) external override onlyGovernance { _addFtso(_ftso, true); } /** * @notice Adds FTSO list to the list of rewarded FTSOs * All ftsos in multi asset ftso must be managed by this ftso manager */ function addFtsosBulk(IIFtso[] memory _ftsos) external override onlyGovernance { for (uint256 i = 0; i < _ftsos.length; i++) { _addFtso(_ftsos[i], true); } } /** * @notice Removes FTSO from the list of the rewarded FTSOs - revert if ftso is used in multi asset ftso * @dev Deactivates _ftso */ function removeFtso(IIFtso _ftso) external override onlyGovernance { ftsoManagement.removeFtso(_ftso); } /** * @notice Replaces one ftso with another * All ftsos in multi asset ftso must be managed by this ftso manager * @dev Deactivates old ftso */ function replaceFtso( IIFtso _ftsoToAdd, bool _copyCurrentPrice, bool _copyAssetOrAssetFtsos ) external override onlyGovernance { _replaceFtso(_ftsoToAdd, _copyCurrentPrice, _copyAssetOrAssetFtsos); } /** * @notice Bulk replaces one ftso with another * All ftsos in multi asset ftso must be managed by this ftso manager * @dev Deactivates old ftsos */ function replaceFtsosBulk( IIFtso[] memory _ftsosToAdd, bool _copyCurrentPrice, bool _copyAssetOrAssetFtsos ) external override onlyGovernance { for (uint256 i = 0; i < _ftsosToAdd.length; i++) { _replaceFtso(_ftsosToAdd[i], _copyCurrentPrice, _copyAssetOrAssetFtsos); } } /** * @notice Deactivates ftsos that are no longer used on ftso registry */ function deactivateFtsos(IIFtso[] memory _ftsos) external onlyGovernance { ftsoManagement.deactivateFtsos(_ftsos); } /** * @notice Set asset for FTSO */ function setFtsoAsset(IIFtso _ftso, IIVPToken _asset) external override onlyGovernance { _ftso.setAsset(_asset); } /** * @notice Set asset FTSOs for FTSO - all ftsos should already be managed by this ftso manager */ function setFtsoAssetFtsos(IIFtso _ftso, IIFtso[] memory _assetFtsos) external override onlyGovernance { ftsoManagement.setFtsoAssetFtsos(_ftso, _assetFtsos); } /** * @notice Set fallback mode */ function setFallbackMode(bool _fallbackMode) external override onlyImmediateGovernance { fallbackMode = _fallbackMode; emit FallbackMode(_fallbackMode); } /** * @notice Set fallback mode for ftso */ function setFtsoFallbackMode(IIFtso _ftso, bool _fallbackMode) external override onlyImmediateGovernance { require(ftsoManagement.managedFtsos[_ftso], ERR_NOT_FOUND); ftsoManagement.ftsoInFallbackMode[_ftso] = _fallbackMode; emit FtsoFallbackMode(_ftso, _fallbackMode); } /** * @notice Sets governance parameters for FTSOs */ function setGovernanceParameters( uint256 _maxVotePowerNatThresholdFraction, uint256 _maxVotePowerAssetThresholdFraction, uint256 _lowAssetUSDThreshold, uint256 _highAssetUSDThreshold, uint256 _highAssetTurnoutThresholdBIPS, uint256 _lowNatTurnoutThresholdBIPS, uint256 _rewardExpiryOffsetSeconds, address[] memory _trustedAddresses ) external override onlyGovernance { require( _maxVotePowerNatThresholdFraction > 0 && _maxVotePowerAssetThresholdFraction > 0 && _highAssetUSDThreshold >= _lowAssetUSDThreshold && _highAssetTurnoutThresholdBIPS <= 1e4 && _lowNatTurnoutThresholdBIPS <= 1e4 && _rewardExpiryOffsetSeconds > 0 && _trustedAddresses.length <= MAX_TRUSTED_ADDRESSES_LENGTH, ERR_GOV_PARAMS_INVALID ); settings._setState( _maxVotePowerNatThresholdFraction, _maxVotePowerAssetThresholdFraction, _lowAssetUSDThreshold, _highAssetUSDThreshold, _highAssetTurnoutThresholdBIPS, _lowNatTurnoutThresholdBIPS, _rewardExpiryOffsetSeconds, _trustedAddresses ); } function setRewardEpochDurationSeconds(uint256 _rewardEpochDurationSeconds) external onlyGovernance { require(_rewardEpochDurationSeconds > 0, ERR_REWARD_EPOCH_DURATION_ZERO); require(_rewardEpochDurationSeconds % priceEpochDurationSeconds == 0, ERR_REWARD_EPOCH_DURATION_CONDITION_INVALID); rewardEpochDurationSeconds = _rewardEpochDurationSeconds; } function setUpdateOnRewardEpochSwitchover(IUpdateValidators _updateValidators) external onlyGovernance { updateOnRewardEpochSwitchover = _updateValidators; } function setVotePowerIntervalFraction(uint256 _votePowerIntervalFraction) external onlyGovernance { require(_votePowerIntervalFraction > 0, ERR_VOTE_POWER_INTERVAL_FRACTION_ZERO); votePowerIntervalFraction = _votePowerIntervalFraction; } function getVotePowerIntervalFraction() external view returns (uint256) { return votePowerIntervalFraction; } function getPriceSubmitter() external view returns (IIPriceSubmitter) { return priceSubmitter; } function getCurrentPriceEpochId() external view override returns (uint256 _priceEpochId) { return _getCurrentPriceEpochId(); } /** * @dev half-closed intervals - end time not included */ function getCurrentPriceEpochData() external view override returns ( uint256 _priceEpochId, uint256 _priceEpochStartTimestamp, uint256 _priceEpochEndTimestamp, uint256 _priceEpochRevealEndTimestamp, uint256 _currentTimestamp ) { uint256 epochId = _getCurrentPriceEpochId(); return ( epochId, firstPriceEpochStartTs + epochId * priceEpochDurationSeconds, firstPriceEpochStartTs + (epochId + 1) * priceEpochDurationSeconds, firstPriceEpochStartTs + (epochId + 1) * priceEpochDurationSeconds + revealEpochDurationSeconds, block.timestamp ); } /** * @notice Gets vote power block of the specified reward epoch * @param _rewardEpoch Reward epoch sequence number */ function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view override returns ( uint256 _votepowerBlock ) { return getRewardEpochData(_rewardEpoch).votepowerBlock; } /** * @notice Return reward epoch that will expire, when new reward epoch is initialized * @return Reward epoch id that will expire next */ function getRewardEpochToExpireNext() external view override returns (uint256) { return nextRewardEpochToExpire; } /* * @notice Returns the list of FTSOs */ function getFtsos() external view override returns (IIFtso[] memory _ftsos) { return _getFtsos(); } function getPriceEpochConfiguration() external view override returns ( uint256 _firstPriceEpochStartTs, uint256 _priceEpochDurationSeconds, uint256 _revealEpochDurationSeconds ) { return (firstPriceEpochStartTs, priceEpochDurationSeconds, revealEpochDurationSeconds); } function getRewardEpochConfiguration() external view override returns ( uint256 _firstRewardEpochStartTs, uint256 _rewardEpochDurationSeconds ) { return (rewardEpochsStartTs, rewardEpochDurationSeconds); } function getFallbackMode() external view override returns ( bool _fallbackMode, IIFtso[] memory _ftsos, bool[] memory _ftsoInFallbackMode ) { _fallbackMode = fallbackMode; _ftsos = _getFtsos(); uint256 len = _ftsos.length; _ftsoInFallbackMode = new bool[](len); for (uint256 i = 0; i < len; i++) { _ftsoInFallbackMode[i] = ftsoManagement.ftsoInFallbackMode[_ftsos[i]]; } } /** * @notice Gets governance parameters for FTSOs */ function getGovernanceParameters() external view returns ( uint256 _maxVotePowerNatThresholdFraction, uint256 _maxVotePowerAssetThresholdFraction, uint256 _lowAssetUSDThreshold, uint256 _highAssetUSDThreshold, uint256 _highAssetTurnoutThresholdBIPS, uint256 _lowNatTurnoutThresholdBIPS, uint256 _rewardExpiryOffsetSeconds, address[] memory _trustedAddresses, bool _initialized, bool _changed ) { return ( settings.maxVotePowerNatThresholdFraction, settings.maxVotePowerAssetThresholdFraction, settings.lowAssetUSDThreshold, settings.highAssetUSDThreshold, settings.highAssetTurnoutThresholdBIPS, settings.lowNatTurnoutThresholdBIPS, settings.rewardExpiryOffsetSeconds, settings.trustedAddresses, settings.initialized, settings.changed ); } function getLastUnprocessedPriceEpochData() external view override returns ( uint256 _lastUnprocessedPriceEpoch, uint256 _lastUnprocessedPriceEpochRevealEnds, bool _lastUnprocessedPriceEpochInitialized ) { return (lastUnprocessedPriceEpoch, lastUnprocessedPriceEpochRevealEnds, lastUnprocessedPriceEpochInitialized); } /** * @notice Returns current reward epoch index (one currently running) */ function getCurrentRewardEpoch() external view override returns (uint256) { require(rewardEpochsLength != 0, ERR_REWARD_EPOCH_NOT_INITIALIZED); return _getCurrentRewardEpochId(); } function rewardEpochs(uint256 _rewardEpochId) external view override returns ( uint256 _votepowerBlock, uint256 _startBlock, uint256 _startTimestamp ) { RewardEpochData memory rewardEpochData = getRewardEpochData(_rewardEpochId); _votepowerBlock = rewardEpochData.votepowerBlock; _startBlock = rewardEpochData.startBlock; _startTimestamp = rewardEpochData.startTimestamp; } function notInitializedFtsos(IIFtso _ftso) external view override returns (bool) { return ftsoManagement.notInitializedFtsos[_ftso]; } function ftsoRegistry() external view returns (IIFtsoRegistry) { return ftsoManagement.ftsoRegistry; } function voterWhitelister() external view returns (IIVoterWhitelister) { return ftsoManagement.voterWhitelister; } /** * @notice Implement this function for updating daemonized contracts through AddressUpdater. */ function getContractName() external pure override returns (string memory) { return "FtsoManager"; } /** * @notice Returns reward epoch data * @param _rewardEpochId Reward epoch id */ function getRewardEpochData(uint256 _rewardEpochId) public view override returns (RewardEpochData memory) { require(_rewardEpochId < rewardEpochsLength, ERR_REWARD_EPOCH_NOT_INITIALIZED); return _getRewardEpoch(_rewardEpochId); } function _rewardEpochSwitchoverTrigger() internal { if (address(updateOnRewardEpochSwitchover) != address(0)) { uint256 currentRewardEpoch = _getCurrentRewardEpochId(); try updateOnRewardEpochSwitchover.updateActiveValidators() { } catch Error(string memory message) { emit UpdatingActiveValidatorsTriggerFailed(currentRewardEpoch); addRevertError(address(updateOnRewardEpochSwitchover), message); } catch { emit UpdatingActiveValidatorsTriggerFailed(currentRewardEpoch); addRevertError(address(updateOnRewardEpochSwitchover), ERR_UPDATE_REWARD_EPOCH_SWITCHOVER_CALL); } } } function _addFtso(IIFtso _ftso, bool _addNewFtso) internal { ftsoManagement.addFtso(settings, _ftso, _addNewFtso, lastUnprocessedPriceEpochInitialized); _initialActivateFtso(_ftso); } function _replaceFtso(IIFtso _ftsoToAdd, bool _copyCurrentPrice, bool _copyAssetOrAssetFtsos) internal { ftsoManagement.replaceFtso(settings, _ftsoToAdd, _copyCurrentPrice, _copyAssetOrAssetFtsos, lastUnprocessedPriceEpochInitialized); _initialActivateFtso(_ftsoToAdd); } function _initialActivateFtso(IIFtso _ftso) internal { _ftso.activateFtso(firstPriceEpochStartTs, priceEpochDurationSeconds, revealEpochDurationSeconds); // Set the vote power block if (rewardEpochsLength != 0) { _ftso.setVotePowerBlock(_getRewardEpoch(_getCurrentRewardEpochId()).votepowerBlock); } } /** * @notice Initializes first reward epoch. Also sets vote power block to FTSOs */ function _initializeFirstRewardEpoch() internal { if (block.timestamp >= rewardEpochsStartTs) { IIFtso[] memory ftsos = _getFtsos(); uint256 numFtsos = ftsos.length; // Prime the reward epoch array with a new reward epoch RewardEpochData memory epochData = RewardEpochData({ votepowerBlock: block.number - 1, startBlock: block.number, startTimestamp: block.timestamp }); rewardEpochsMapping[rewardEpochsLength] = epochData; rewardEpochsLength++; for (uint256 i = 0; i < numFtsos; ++i) { ftsos[i].setVotePowerBlock(epochData.votepowerBlock); } currentRewardEpochEnds = rewardEpochsStartTs + rewardEpochDurationSeconds; } } /** * @notice Finalizes reward epoch */ function _finalizeRewardEpoch() internal { IIFtso[] memory ftsos = _getFtsos(); uint256 numFtsos = ftsos.length; uint256 lastRandom = block.timestamp; lastRandom += priceSubmitter.getCurrentRandom(); lastRandom = uint256(keccak256(abi.encode(lastRandom))); // @dev when considering block boundary for vote power block: // - if far from now, it doesn't reflect last vote power changes // - if too small, possible loan attacks. // IMPORTANT: currentRewardEpoch is actually the one just getting finalized! uint256 votepowerBlockBoundary = (block.number - _getRewardEpoch(_getCurrentRewardEpochId()).startBlock) / votePowerIntervalFraction; // note: votePowerIntervalFraction > 0 if (votepowerBlockBoundary == 0) { votepowerBlockBoundary = 1; } //slither-disable-next-line weak-prng // lastRandom calculated from ftso inputs uint256 votepowerBlocksAgo = lastRandom % votepowerBlockBoundary; // prevent block.number becoming votePowerBlock // if lastRandom % votepowerBlockBoundary == 0 if (votepowerBlocksAgo == 0) { votepowerBlocksAgo = 1; } RewardEpochData memory epochData = RewardEpochData({ votepowerBlock: block.number - votepowerBlocksAgo, startBlock: block.number, startTimestamp: block.timestamp }); rewardEpochsMapping[rewardEpochsLength] = epochData; rewardEpochsLength++; for (uint256 i = 0; i < numFtsos; i++) { ftsos[i].setVotePowerBlock(epochData.votepowerBlock); } emit RewardEpochFinalized(epochData.votepowerBlock, epochData.startBlock); // Advance reward epoch end-time currentRewardEpochEnds += rewardEpochDurationSeconds; } /** * @notice Closes expired reward epochs */ function _closeExpiredRewardEpochs() internal { uint256 currentRewardEpoch = _getCurrentRewardEpochId(); uint256 expiryThreshold = block.timestamp - settings.rewardExpiryOffsetSeconds; // NOTE: start time of (i+1)th reward epoch is the end time of i-th // This loop is clearly bounded by the value currentRewardEpoch, which is // always kept to the value of rewardEpochs.length - 1 in code and this value // does not change in the loop. while ( nextRewardEpochToExpire < currentRewardEpoch && _getRewardEpoch(nextRewardEpochToExpire + 1).startTimestamp <= expiryThreshold) { // Note: Since nextRewardEpochToExpire + 1 starts at that time // nextRewardEpochToExpire ends strictly before expiryThreshold, try rewardManager.closeExpiredRewardEpoch(nextRewardEpochToExpire) { nextRewardEpochToExpire++; } catch Error(string memory message) { // closing of expired failed, which is not critical // just emit event for diagnostics emit ClosingExpiredRewardEpochFailed(nextRewardEpochToExpire); addRevertError(address(rewardManager), message); // Do not proceed with the loop. break; } catch { emit ClosingExpiredRewardEpochFailed(nextRewardEpochToExpire); addRevertError(address(rewardManager), ERR_CLOSING_EXPIRED_REWARD_EPOCH_FAIL); // Do not proceed with the loop. break; } } } /** * @notice Performs any cleanup needed immediately after a reward epoch is finalized */ function _cleanupOnRewardEpochFinalization() internal { uint256 cleanupBlock = _getRewardEpoch(nextRewardEpochToExpire).votepowerBlock; try cleanupBlockNumberManager.setCleanUpBlockNumber(cleanupBlock) { } catch Error(string memory message) { // cleanup block number manager call failed, which is not critical // just emit event for diagnostics emit CleanupBlockNumberManagerFailedForBlock(cleanupBlock); addRevertError(address(cleanupBlockNumberManager), message); } catch { emit CleanupBlockNumberManagerFailedForBlock(cleanupBlock); addRevertError(address(cleanupBlockNumberManager), ERR_SET_CLEANUP_BLOCK_FAIL); } } function _finalizePriceEpochFailed(IIFtso ftso, string memory message) internal { emit FinalizingPriceEpochFailed( ftso, lastUnprocessedPriceEpoch, IFtso.PriceFinalizationType.WEIGHTED_MEDIAN ); addRevertError(address(ftso), message); _fallbackFinalizePriceEpoch(ftso); } /** * @notice Finalizes price epoch */ function _finalizePriceEpoch() internal { IIFtso[] memory ftsos = _getFtsos(); uint256 numFtsos = ftsos.length; // Are there any FTSOs to process? if (numFtsos > 0 && !fallbackMode) { // choose winning ftso uint256 chosenFtsoId; if (lastRewardedFtsoAddress == address(0)) { // pump not yet primed //slither-disable-next-line weak-prng // only used for first epoch chosenFtsoId = uint256(keccak256(abi.encode( block.difficulty, block.timestamp ))) % numFtsos; } else { // at least one finalize with real FTSO uint256 currentRandom = priceSubmitter.getCurrentRandom(); //slither-disable-next-line weak-prng // random calculated safely from inputs chosenFtsoId = uint256(keccak256(abi.encode( currentRandom, block.timestamp ))) % numFtsos; } address[] memory addresses; uint256[] memory weights; uint256 totalWeight; // On the off chance that the winning FTSO does not have any // recipient within the truncated price distribution to // receive rewards, find the next FTSO that does have reward // recipients and declare it the winner. Start with the next ftso. bool wasDistributed = false; address rewardedFtsoAddress = address(0); for (uint256 i = 0; i < numFtsos; i++) { //slither-disable-next-line weak-prng // not a random, just choosing next uint256 id = (chosenFtsoId + i) % numFtsos; IIFtso ftso = ftsos[id]; // skip finalizing ftso, as it is not initialized for reveal and tx would revert if (ftsoManagement.notInitializedFtsos[ftso]) { delete ftsoManagement.notInitializedFtsos[ftso]; continue; } try ftso.finalizePriceEpoch(lastUnprocessedPriceEpoch, !wasDistributed) returns ( address[] memory _addresses, uint256[] memory _weights, uint256 _totalWeight ) { if (!wasDistributed && _addresses.length > 0) { // change also in FTSO if condition changes (addresses, weights, totalWeight) = (_addresses, _weights, _totalWeight); wasDistributed = true; rewardedFtsoAddress = address(ftso); } } catch Error(string memory message) { _finalizePriceEpochFailed(ftso, message); } catch { _finalizePriceEpochFailed(ftso, ERR_PRICE_EPOCH_FINALIZE_FAIL); } } uint256 currentRewardEpoch = _getCurrentRewardEpochId(); if (wasDistributed) { try rewardManager.distributeRewards( addresses, weights, totalWeight, lastUnprocessedPriceEpoch, rewardedFtsoAddress, priceEpochDurationSeconds, currentRewardEpoch, _getPriceEpochEndTime(lastUnprocessedPriceEpoch) - 1, // actual end time (included) _getRewardEpoch(currentRewardEpoch).votepowerBlock) { } catch Error(string memory message) { emit DistributingRewardsFailed(rewardedFtsoAddress, lastUnprocessedPriceEpoch); addRevertError(address(rewardManager), message); } catch { emit DistributingRewardsFailed(rewardedFtsoAddress, lastUnprocessedPriceEpoch); addRevertError(address(rewardManager), ERR_DISTRIBUTE_REWARD_FAIL); } } else { // If here, it means that no FTSO was initialized, or no FTSO had a recipient // eligible to receive rewards. And if so, burn rewards for this price epoch. _accrueUnearnedRewards(); } lastRewardedFtsoAddress = rewardedFtsoAddress; emit PriceEpochFinalized(rewardedFtsoAddress, currentRewardEpoch); } else { // only for fallback mode for (uint256 i = 0; i < numFtsos; i++) { IIFtso ftso = ftsos[i]; // skip finalizing ftso, as it is not initialized for reveal and tx would revert if (ftsoManagement.notInitializedFtsos[ftso]) { delete ftsoManagement.notInitializedFtsos[ftso]; continue; } _fallbackFinalizePriceEpoch(ftso); } // Because FTSO manager in fallback, burn rewards for this price epoch. _accrueUnearnedRewards(); lastRewardedFtsoAddress = address(0); emit PriceEpochFinalized(address(0), _getCurrentRewardEpochId()); } lastUnprocessedPriceEpochInitialized = false; } function _accrueUnearnedRewards() internal { try rewardManager.accrueUnearnedRewards( lastUnprocessedPriceEpoch, priceEpochDurationSeconds, _getPriceEpochEndTime(lastUnprocessedPriceEpoch) - 1) { // actual end time (included) } catch Error(string memory message) { emit AccruingUnearnedRewardsFailed(lastUnprocessedPriceEpoch); addRevertError(address(rewardManager), message); } catch { emit AccruingUnearnedRewardsFailed(lastUnprocessedPriceEpoch); addRevertError(address(rewardManager), ERR_ACCRUE_UNEARNED_REWARD_FAIL); } } function _fallbackFinalizePriceEpochFailed(IIFtso _ftso, string memory message) internal { emit FinalizingPriceEpochFailed( _ftso, lastUnprocessedPriceEpoch, IFtso.PriceFinalizationType.TRUSTED_ADDRESSES ); addRevertError(address(_ftso), message); // if reverts we want to propagate up to daemon _ftso.forceFinalizePriceEpoch(lastUnprocessedPriceEpoch); } function _fallbackFinalizePriceEpoch(IIFtso _ftso) internal { try _ftso.fallbackFinalizePriceEpoch(lastUnprocessedPriceEpoch) { } catch Error(string memory message) { _fallbackFinalizePriceEpochFailed(_ftso, message); } catch { _fallbackFinalizePriceEpochFailed(_ftso, ERR_FALLBACK_FINALIZE_FAIL); } } /** * @notice Initializes epoch states in FTSOs for reveal. * Prior to initialization it sets governance parameters, if * governance has changed them. It also sets price submitter trusted addresses. */ function _initializeCurrentEpochFTSOStatesForReveal() internal { if (settings.changed) { priceSubmitter.setTrustedAddresses(settings.trustedAddresses); } IIFtso[] memory ftsos = _getFtsos(); uint256 numFtsos = ftsos.length; // circulating supply is used only when ftso is not in fallback mode uint256 circulatingSupplyNat; if (numFtsos > 0 && !fallbackMode) { uint256 votePowerBlock = _getRewardEpoch(_getCurrentRewardEpochId()).votepowerBlock; circulatingSupplyNat = supply.getCirculatingSupplyAtCached(votePowerBlock); } for (uint256 i = 0; i < numFtsos; i++) { IIFtso ftso = ftsos[i]; if (settings.changed) { ftso.configureEpochs( settings.maxVotePowerNatThresholdFraction, settings.maxVotePowerAssetThresholdFraction, settings.lowAssetUSDThreshold, settings.highAssetUSDThreshold, settings.highAssetTurnoutThresholdBIPS, settings.lowNatTurnoutThresholdBIPS, settings.trustedAddresses ); } try ftso.initializeCurrentEpochStateForReveal( circulatingSupplyNat, fallbackMode || ftsoManagement.ftsoInFallbackMode[ftso]) { } catch Error(string memory message) { _initializeCurrentEpochStateForRevealFailed(ftso, message); } catch { _initializeCurrentEpochStateForRevealFailed(ftso, ERR_INIT_EPOCH_REVEAL_FAIL); } } settings.changed = false; // Advance price epoch id and end-time uint256 currentPriceEpochId = _getCurrentPriceEpochId(); lastUnprocessedPriceEpoch = currentPriceEpochId; lastUnprocessedPriceEpochRevealEnds = _getPriceEpochRevealEndTime(currentPriceEpochId); lastUnprocessedPriceEpochInitialized = true; } function _initializeCurrentEpochStateForRevealFailed(IIFtso ftso, string memory message) internal { emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId()); addRevertError(address(ftso), message); // if it was already called with fallback = true, just mark as not initialized, else retry if (fallbackMode || ftsoManagement.ftsoInFallbackMode[ftso]) { ftsoManagement.notInitializedFtsos[ftso] = true; } else { try ftso.initializeCurrentEpochStateForReveal(0, true) { } catch Error(string memory message1) { ftsoManagement.notInitializedFtsos[ftso] = true; emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId()); addRevertError(address(ftso), message1); } catch { ftsoManagement.notInitializedFtsos[ftso] = true; emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId()); addRevertError(address(ftso), ERR_FALLBACK_INIT_EPOCH_REVEAL_FAIL); } } } /** * @notice Implementation of the AddressUpdatable abstract method. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { rewardManager = IIFtsoRewardManager( _getContractAddress(_contractNameHashes, _contractAddresses, "FtsoRewardManager")); supply = IISupply( _getContractAddress(_contractNameHashes, _contractAddresses, "Supply")); cleanupBlockNumberManager = CleanupBlockNumberManager( _getContractAddress(_contractNameHashes, _contractAddresses, "CleanupBlockNumberManager")); ftsoManagement.ftsoRegistry = IIFtsoRegistry( _getContractAddress(_contractNameHashes, _contractAddresses, "FtsoRegistry")); ftsoManagement.voterWhitelister = IIVoterWhitelister( _getContractAddress(_contractNameHashes, _contractAddresses, "VoterWhitelister")); } /** * @notice Returns current reward epoch id without additional checks */ function _getCurrentRewardEpochId() internal view returns (uint256) { return rewardEpochsLength - 1; } /** * Get reward epoch from current ftso manager or from old one if no data in current */ function _getRewardEpoch(uint256 _rewardEpochId) internal view returns (RewardEpochData memory _rewardEpoch) { _rewardEpoch = rewardEpochsMapping[_rewardEpochId]; if (_rewardEpoch.startTimestamp == 0) { (uint256 vpBlock, uint256 sBlock, uint256 sTimestamp) = oldFtsoManager.rewardEpochs(_rewardEpochId); _rewardEpoch = RewardEpochData({ votepowerBlock: vpBlock, startBlock: sBlock, startTimestamp: sTimestamp }); } } /** * @notice Returns price epoch reveal end time. * @param _priceEpochId The price epoch id. * @dev half-closed interval - end time not included */ function _getPriceEpochRevealEndTime(uint256 _priceEpochId) internal view returns (uint256) { return firstPriceEpochStartTs + (_priceEpochId + 1) * priceEpochDurationSeconds + revealEpochDurationSeconds; } /** * @notice Returns price epoch end time. * @param _forPriceEpochId The price epoch id of the end time to fetch. * @dev half-closed interval - end time not included */ function _getPriceEpochEndTime(uint256 _forPriceEpochId) internal view returns (uint256) { return firstPriceEpochStartTs + ((_forPriceEpochId + 1) * priceEpochDurationSeconds); } /** * @notice Returns current price epoch id. The calculation in this function * should fully match to definition of current epoch id in FTSO contracts. */ function _getCurrentPriceEpochId() internal view returns (uint256) { return (block.timestamp - firstPriceEpochStartTs) / priceEpochDurationSeconds; } function _getFtsos() internal view returns (IIFtso[] memory) { return ftsoManagement.ftsoRegistry.getSupportedFtsos(); } }
contracts/tokenPools/interface/IITokenPool.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IITokenPool { /** * @notice Return token pool supply data * @return _lockedFundsWei Funds that are intentionally locked in the token pool * and not part of circulating supply * @return _totalInflationAuthorizedWei Total inflation authorized amount (wei) * @return _totalClaimedWei Total claimed amount (wei) */ function getTokenPoolSupplyData() external returns ( uint256 _lockedFundsWei, uint256 _totalInflationAuthorizedWei, uint256 _totalClaimedWei ); }
contracts/utils/interface/IIVoterWhitelister.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IVoterWhitelister.sol"; interface IIVoterWhitelister is IVoterWhitelister { /** * Set the maximum number of voters in the whitelist for FTSO at index `_ftsoIndex`. * Possibly removes several voters with the least votepower from the whitelist. * Only governance can call this method. */ function setMaxVotersForFtso(uint256 _ftsoIndex, uint256 _newMaxVoters) external; /** * Set the maximum number of voters in the whitelist for a new FTSO. * Only governance can call this method. */ function setDefaultMaxVotersForFtso(uint256 _defaultMaxVotersForFtso) external; /** * Create whitelist with default size for ftso. * Only ftso manager can call this method. */ function addFtso(uint256 _ftsoIndex) external; /** * Clear whitelist for ftso at `_ftsoIndex`. * Only ftso manager can call this method. */ function removeFtso(uint256 _ftsoIndex) external; /** * Remove `_trustedAddress` from whitelist for ftso at `_ftsoIndex`. */ function removeTrustedAddressFromWhitelist(address _trustedAddress, uint256 _ftsoIndex) external; }
contracts/ftso/interface/IIFtsoManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; import "../../ftso/interface/IIFtso.sol"; import "../../userInterfaces/IFtsoManager.sol"; import "../../genesis/interface/IFlareDaemonize.sol"; import "../../token/interface/IIVPToken.sol"; interface IIFtsoManager is IFtsoManager, IFlareDaemonize { struct RewardEpochData { uint256 votepowerBlock; uint256 startBlock; uint256 startTimestamp; } event ClosingExpiredRewardEpochFailed(uint256 rewardEpoch); event CleanupBlockNumberManagerFailedForBlock(uint256 blockNumber); event UpdatingActiveValidatorsTriggerFailed(uint256 rewardEpoch); event FtsoDeactivationFailed(IIFtso ftso); function activate() external; function setInitialRewardData( uint256 _nextRewardEpochToExpire, uint256 _rewardEpochsLength, uint256 _currentRewardEpochEnds ) external; function setGovernanceParameters( uint256 _maxVotePowerNatThresholdFraction, uint256 _maxVotePowerAssetThresholdFraction, uint256 _lowAssetUSDThreshold, uint256 _highAssetUSDThreshold, uint256 _highAssetTurnoutThresholdBIPS, uint256 _lowNatTurnoutThresholdBIPS, uint256 _rewardExpiryOffsetSeconds, address[] memory _trustedAddresses ) external; function addFtso(IIFtso _ftso) external; function addFtsosBulk(IIFtso[] memory _ftsos) external; function removeFtso(IIFtso _ftso) external; function replaceFtso( IIFtso _ftsoToAdd, bool copyCurrentPrice, bool copyAssetOrAssetFtsos ) external; function replaceFtsosBulk( IIFtso[] memory _ftsosToAdd, bool copyCurrentPrice, bool copyAssetOrAssetFtsos ) external; function setFtsoAsset(IIFtso _ftso, IIVPToken _asset) external; function setFtsoAssetFtsos(IIFtso _ftso, IIFtso[] memory _assetFtsos) external; function setFallbackMode(bool _fallbackMode) external; function setFtsoFallbackMode(IIFtso _ftso, bool _fallbackMode) external; function notInitializedFtsos(IIFtso) external view returns (bool); function getRewardEpochData(uint256 _rewardEpochId) external view returns (RewardEpochData memory); function currentRewardEpochEnds() external view returns (uint256); function getLastUnprocessedPriceEpochData() external view returns( uint256 _lastUnprocessedPriceEpoch, uint256 _lastUnprocessedPriceEpochRevealEnds, bool _lastUnprocessedPriceEpochInitialized ); function rewardEpochsStartTs() external view returns(uint256); function rewardEpochDurationSeconds() external view returns(uint256); function rewardEpochs(uint256 _rewardEpochId) external view returns ( uint256 _votepowerBlock, uint256 _startBlock, uint256 _startTimestamp ); }
contracts/governance/implementation/Governed.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import { GovernedBase } from "./GovernedBase.sol"; /** * @title Governed * @dev For deployed, governed contracts, enforce a non-zero address at create time. **/ contract Governed is GovernedBase { constructor(address _governance) GovernedBase(_governance) { require(_governance != address(0), "_governance zero"); } }
contracts/genesis/interface/IIPriceSubmitter.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IPriceSubmitter.sol"; interface IIPriceSubmitter is IPriceSubmitter { /** * Set trusted addresses that are always allowed to submit and reveal. * Only ftso manager can call this method. */ function setTrustedAddresses(address[] memory _trustedAddresses) external; /** * Called from whitelister when new voter has been whitelisted. */ function voterWhitelisted(address _voter, uint256 _ftsoIndex) external; /** * Called from whitelister when one or more voters have been removed. */ function votersRemovedFromWhitelist(address[] memory _voters, uint256 _ftsoIndex) external; /** * Returns a list of trusted addresses that are always allowed to submit and reveal. */ function getTrustedAddresses() external view returns (address[] memory); }
contracts/token/interface/IIGovernanceVotePower.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IVPToken.sol"; import "../../userInterfaces/IGovernanceVotePower.sol"; interface IIGovernanceVotePower is IGovernanceVotePower { /** * Event triggered when an delegator's balance changes. * * Note: the event is always emitted from `GovernanceVotePower`. */ event DelegateVotesChanged( address indexed delegate, uint256 previousBalance, uint256 newBalance ); /** * Event triggered when an account delegates to another account. * * Note: the event is always emitted from `GovernanceVotePower`. */ event DelegateChanged( address indexed delegator, address indexed fromDelegate, address indexed toDelegate ); /** * Update vote powers when tokens are transfered. **/ function updateAtTokenTransfer( address _from, address _to, uint256 _fromBalance, uint256 _toBalance, uint256 _amount ) external; /** * Set the cleanup block number. * Historic data for the blocks before `cleanupBlockNumber` can be erased, * history before that block should never be used since it can be inconsistent. * In particular, cleanup block number must be before current vote power block. * @param _blockNumber The new cleanup block number. */ function setCleanupBlockNumber(uint256 _blockNumber) external; /** * Set the contract that is allowed to call history cleaning methods. */ function setCleanerContract(address _cleanerContract) external; /** * @notice Get the token that this governance vote power contract belongs to. */ function ownerToken() external view returns (IVPToken); function getCleanupBlockNumber() external view returns(uint256); }
contracts/inflation/interface/IISupply.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IISupply { /** * @notice Updates circulating supply * @dev Also updates the burn address amount */ function updateCirculatingSupply() external; /** * @notice Updates authorized inflation and circulating supply - emits event if error * @param _inflationAuthorizedWei Authorized inflation * @dev Also updates the burn address amount */ function updateAuthorizedInflationAndCirculatingSupply(uint256 _inflationAuthorizedWei) external; /** * @notice Get approximate circulating supply for given block number from cache - only past block * @param _blockNumber Block number * @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber */ function getCirculatingSupplyAtCached(uint256 _blockNumber) external returns(uint256 _circulatingSupplyWei); /** * @notice Get approximate circulating supply for given block number * @param _blockNumber Block number * @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber */ function getCirculatingSupplyAt(uint256 _blockNumber) external view returns(uint256 _circulatingSupplyWei); /** * @notice Get total inflatable balance (initial genesis amount + total authorized inflation) * @return _inflatableBalanceWei Return inflatable balance */ function getInflatableBalance() external view returns(uint256 _inflatableBalanceWei); }
contracts/userInterfaces/IVPContractEvents.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IVPContractEvents { /** * Event triggered when an account delegates or undelegates another account. * Definition: `votePowerFromTo(from, to)` is `changed` from `priorVotePower` to `newVotePower`. * For undelegation, `newVotePower` is 0. * * Note: the event is always emitted from VPToken's `writeVotePowerContract`. */ event Delegate(address indexed from, address indexed to, uint256 priorVotePower, uint256 newVotePower); /** * Event triggered only when account `delegator` revokes delegation to `delegatee` * for a single block in the past (typically the current vote block). * * Note: the event is always emitted from VPToken's `writeVotePowerContract` and/or `readVotePowerContract`. */ event Revoke(address indexed delegator, address indexed delegatee, uint256 votePower, uint256 blockNumber); }
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)); } }
contracts/inflation/interface/IIInflationReceiver.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIInflationReceiver { /** * Notify the receiver that it is entitled to receive `_toAuthorizeWei` inflation amount. * @param _toAuthorizeWei the amount of inflation that can be awarded in the coming day */ function setDailyAuthorizedInflation(uint256 _toAuthorizeWei) external; /** * Receive native tokens from inflation. */ function receiveInflation() external payable; /** * Inflation receivers have a reference to the Inflation contract. */ function getInflationAddress() external returns(address); /** * Implement this function for updating inflation receiver contracts through AddressUpdater. */ function getContractName() external view returns (string memory); }
contracts/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/ftso/lib/FtsoManagement.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "../interface/IIFtsoManager.sol"; import "../interface/IIFtsoManagerV1.sol"; import "../interface/IIFtso.sol"; import "../lib/FtsoManagerSettings.sol"; import "../../genesis/implementation/FlareDaemon.sol"; import "../../genesis/interface/IIPriceSubmitter.sol"; import "../../governance/implementation/Governed.sol"; import "../../inflation/interface/IISupply.sol"; import "../../tokenPools/interface/IIFtsoRewardManager.sol"; import "../../token/implementation/CleanupBlockNumberManager.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../../utils/implementation/GovernedAndFlareDaemonized.sol"; import "../../utils/implementation/RevertErrorTracking.sol"; import "../../utils/interface/IIFtsoRegistry.sol"; import "../../utils/interface/IIVoterWhitelister.sol"; import "../../utils/interface/IUpdateValidators.sol"; library FtsoManagement { using FtsoManagerSettings for FtsoManagerSettings.State; struct State { mapping(IIFtso => bool) managedFtsos; mapping(IIFtso => bool) notInitializedFtsos; mapping(IIFtso => bool) ftsoInFallbackMode; IIFtsoRegistry ftsoRegistry; IIVoterWhitelister voterWhitelister; } string internal constant ERR_GOV_PARAMS_NOT_INIT_FOR_FTSOS = "Gov. params not initialized"; string internal constant ERR_ASSET_FTSO_NOT_MANAGED = "Asset FTSO not managed"; string internal constant ERR_ALREADY_ADDED = "Already added"; string internal constant ERR_FTSO_ASSET_FTSO_ZERO = "Asset ftsos list empty"; string internal constant ERR_FTSO_EQUALS_ASSET_FTSO = "ftso equals asset ftso"; // libraries cannot emit event from interfaces, so we have to copy events here event FtsoAdded(IIFtso ftso, bool add); // copied from IFtsoManager.sol event FtsoDeactivationFailed(IIFtso ftso); // copied from IIFtsoManager.sol function addFtso( State storage _state, FtsoManagerSettings.State storage _settings, IIFtso _ftso, bool _addNewFtso, bool _lastUnprocessedPriceEpochInitialized ) public { require(_settings.initialized, ERR_GOV_PARAMS_NOT_INIT_FOR_FTSOS); _checkAssetFtsosAreManaged(_state, _ftso.getAssetFtsos()); if (_addNewFtso) { // Check if symbol already exists in registry bytes32 symbol = keccak256(abi.encode(_ftso.symbol())); string[] memory supportedSymbols = _state.ftsoRegistry.getSupportedSymbols(); uint256 len = supportedSymbols.length; while (len > 0) { --len; if (keccak256(abi.encode(supportedSymbols[len])) == symbol) { revert(ERR_ALREADY_ADDED); } } } // Configure _ftso.configureEpochs( _settings.maxVotePowerNatThresholdFraction, _settings.maxVotePowerAssetThresholdFraction, _settings.lowAssetUSDThreshold, _settings.highAssetUSDThreshold, _settings.highAssetTurnoutThresholdBIPS, _settings.lowNatTurnoutThresholdBIPS, _settings.trustedAddresses ); // skip first round of price finalization if price epoch was already initialized for reveal _state.notInitializedFtsos[_ftso] = _lastUnprocessedPriceEpochInitialized; _state.managedFtsos[_ftso] = true; uint256 ftsoIndex = _state.ftsoRegistry.addFtso(_ftso); // When a new ftso is added we also add it to the voter whitelister contract if (_addNewFtso) { _state.voterWhitelister.addFtso(ftsoIndex); } emit FtsoAdded(_ftso, true); } /** * @notice Replaces one ftso with another - symbols must match * All ftsos in multi asset ftso must be managed by this ftso manager * @dev Deactivates old ftso */ function replaceFtso( State storage _state, FtsoManagerSettings.State storage _settings, IIFtso _ftsoToAdd, bool _copyCurrentPrice, bool _copyAssetOrAssetFtsos, bool _lastUnprocessedPriceEpochInitialized ) public { IIFtso ftsoToRemove = _state.ftsoRegistry.getFtsoBySymbol(_ftsoToAdd.symbol()); if (_copyCurrentPrice) { (uint256 currentPrice, uint256 timestamp) = ftsoToRemove.getCurrentPrice(); _ftsoToAdd.updateInitialPrice(currentPrice, timestamp); } if (_copyAssetOrAssetFtsos) { IIVPToken asset = ftsoToRemove.getAsset(); if (address(asset) != address(0)) { // copy asset if exists _ftsoToAdd.setAsset(asset); } else { // copy assetFtsos list if not empty IIFtso[] memory assetFtsos = ftsoToRemove.getAssetFtsos(); if (assetFtsos.length > 0) { _ftsoToAdd.setAssetFtsos(assetFtsos); } } } // Add without duplicate check addFtso(_state, _settings, _ftsoToAdd, false, _lastUnprocessedPriceEpochInitialized); // replace old contract with the new one in multi asset ftsos IIFtso[] memory contracts = _state.ftsoRegistry.getSupportedFtsos(); uint256 ftsosLen = contracts.length; for (uint256 i = 0; i < ftsosLen; i++) { IIFtso ftso = contracts[i]; if (ftso.ftsoManager() != address(this)) { // it cannot be updated and will be replaced continue; } IIFtso[] memory assetFtsos = ftso.getAssetFtsos(); uint256 assetFtsosLen = assetFtsos.length; if (assetFtsosLen > 0) { bool changed = false; for (uint256 j = 0; j < assetFtsosLen; j++) { if (assetFtsos[j] == ftsoToRemove) { assetFtsos[j] = _ftsoToAdd; changed = true; } } if (changed) { ftso.setAssetFtsos(assetFtsos); } } } // cleanup old contract cleanFtso(_state, ftsoToRemove); } function deactivateFtsos( State storage _state, IIFtso[] memory _ftsos ) public { uint256 len = _ftsos.length; while(len > 0) { len--; IIFtso ftso = _ftsos[len]; try _state.ftsoRegistry.getFtsoBySymbol(ftso.symbol()) returns (IIFtso _ftso) { if (_ftso != ftso) { // deactivate ftso if it was already replaced on ftso registry ftso.deactivateFtso(); delete _state.ftsoInFallbackMode[ftso]; delete _state.notInitializedFtsos[ftso]; delete _state.managedFtsos[ftso]; } else { // ftso still in use on ftso registy - it could be removed using removeFtso call emit FtsoDeactivationFailed(ftso); } } catch { // deactivate ftso if ftso symbol is not used anymore on ftso registry ftso.deactivateFtso(); delete _state.ftsoInFallbackMode[ftso]; delete _state.notInitializedFtsos[ftso]; delete _state.managedFtsos[ftso]; } } } /** * @notice Removes FTSO from the list of the rewarded FTSOs - revert if ftso is used in multi asset ftso * @dev Deactivates _ftso */ function removeFtso( State storage _state, IIFtso _ftso ) public { uint256 ftsoIndex = _state.ftsoRegistry.getFtsoIndex(_ftso.symbol()); _state.voterWhitelister.removeFtso(ftsoIndex); _state.ftsoRegistry.removeFtso(_ftso); cleanFtso(_state, _ftso); } function cleanFtso( State storage _state, IIFtso _ftso ) public { // Since this is as mapping, we can also just delete it, as false is default value for non-existing keys delete _state.ftsoInFallbackMode[_ftso]; delete _state.notInitializedFtsos[_ftso]; delete _state.managedFtsos[_ftso]; // may fail if not managed by current ftso manager (can happen in redeploy) if (_ftso.ftsoManager() == address(this)) { _ftso.deactivateFtso(); _checkMultiAssetFtsosAreManaged(_state, _state.ftsoRegistry.getSupportedFtsos()); } else { // do nothing, old ftso not deactivated, but actually it is not a problem, just emit an event emit FtsoDeactivationFailed(_ftso); } emit FtsoAdded(_ftso, false); } /** * @notice Set asset FTSOs for FTSO - all ftsos should already be managed by this ftso manager */ function setFtsoAssetFtsos( State storage _state, IIFtso _ftso, IIFtso[] memory _assetFtsos ) public { uint256 len = _assetFtsos.length; require(len > 0, ERR_FTSO_ASSET_FTSO_ZERO); for (uint256 i = 0; i < len; i++) { if (_ftso == _assetFtsos[i]) { revert(ERR_FTSO_EQUALS_ASSET_FTSO); } } if (_state.managedFtsos[_ftso]) { _checkAssetFtsosAreManaged(_state, _assetFtsos); } _ftso.setAssetFtsos(_assetFtsos); } /** * @notice Check if asset ftsos are managed by this ftso manager, revert otherwise */ function _checkAssetFtsosAreManaged( State storage _state, IIFtso[] memory _assetFtsos ) internal view { uint256 len = _assetFtsos.length; for (uint256 i = 0; i < len; i++) { if (!_state.managedFtsos[_assetFtsos[i]]) { revert(ERR_ASSET_FTSO_NOT_MANAGED); } } } /** * @notice Check if all multi asset ftsos are managed by this ftso manager, revert otherwise */ function _checkMultiAssetFtsosAreManaged( State storage _state, IIFtso[] memory _ftsos ) internal view { uint256 len = _ftsos.length; for (uint256 i = 0; i < len; i++) { _checkAssetFtsosAreManaged(_state, _ftsos[i].getAssetFtsos()); } } }
contracts/token/implementation/CleanupBlockNumberManager.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../../governance/implementation/Governed.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../../token/interface/IICleanable.sol"; /** * @title Token history cleanup manager * @notice Maintains the list of cleanable tokens for which history cleanup can be collectively cleaned u */ contract CleanupBlockNumberManager is Governed, AddressUpdatable { string internal constant ERR_CONTRACT_NOT_FOUND = "contract not found"; string internal constant ERR_TRIGGER_CONTRACT_ONLY = "trigger contract only"; IICleanable[] public registeredTokens; address public triggerContract; string public triggerContractName; // needed for updating trigger contract through AddressUpdater call event RegistrationUpdated (IICleanable theContract, bool add); event CleanupBlockNumberSet (IICleanable theContract, uint256 blockNumber, bool success); modifier onlyTrigger { require(msg.sender == triggerContract, ERR_TRIGGER_CONTRACT_ONLY); _; } constructor( address _governance, address _addressUpdater, string memory _triggerContractName ) Governed(_governance) AddressUpdatable(_addressUpdater) { triggerContractName = _triggerContractName; } /** * @notice Register a contract of which history cleanup index is to be managed * @param _cleanableToken The address of the contract to be managed. * @dev when using this function take care that call of setCleanupBlockNumber * is permitted by this object */ function registerToken(IICleanable _cleanableToken) external onlyGovernance { uint256 len = registeredTokens.length; for (uint256 i = 0; i < len; i++) { if (_cleanableToken == registeredTokens[i]) { return; // already registered } } registeredTokens.push(_cleanableToken); emit RegistrationUpdated (_cleanableToken, true); } /** * @notice Unregiseter a contract from history cleanup index management * @param _cleanableToken The address of the contract to unregister. */ function unregisterToken(IICleanable _cleanableToken) external onlyGovernance { uint256 len = registeredTokens.length; for (uint256 i = 0; i < len; i++) { if (_cleanableToken == registeredTokens[i]) { registeredTokens[i] = registeredTokens[len -1]; registeredTokens.pop(); emit RegistrationUpdated (_cleanableToken, false); return; } } revert(ERR_CONTRACT_NOT_FOUND); } /** * @notice Sets clean up block number on managed cleanable tokens * @param _blockNumber cleanup block number */ function setCleanUpBlockNumber(uint256 _blockNumber) external onlyTrigger { uint256 len = registeredTokens.length; for (uint256 i = 0; i < len; i++) { try registeredTokens[i].setCleanupBlockNumber(_blockNumber) { emit CleanupBlockNumberSet(registeredTokens[i], _blockNumber, true); } catch { emit CleanupBlockNumberSet(registeredTokens[i], _blockNumber, false); } } } /** * @notice Implementation of the AddressUpdatable abstract method. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { triggerContract = _getContractAddress(_contractNameHashes, _contractAddresses, triggerContractName); } }
contracts/tokenPools/interface/IIFtsoRewardManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IFtsoRewardManager.sol"; import "../interface/IITokenPool.sol"; import "../../inflation/interface/IIInflationReceiver.sol"; interface IIFtsoRewardManager is IFtsoRewardManager, IIInflationReceiver, IITokenPool { event DailyAuthorizedInflationSet(uint256 authorizedAmountWei); event InflationReceived(uint256 amountReceivedWei); event RewardsBurned(uint256 amountBurnedWei); function activate() external; function enableClaims() external; function deactivate() external; function closeExpiredRewardEpoch(uint256 _rewardEpochId) external; function distributeRewards( address[] memory addresses, uint256[] memory weights, uint256 totalWeight, uint256 epochId, address ftso, uint256 priceEpochDurationSeconds, uint256 currentRewardEpoch, uint256 priceEpochEndTime, uint256 votePowerBlock ) external; function accrueUnearnedRewards( uint256 epochId, uint256 priceEpochDurationSeconds, uint256 priceEpochEndTime ) external; function firstClaimableRewardEpoch() external view returns (uint256); /** * @notice Returns the information on unclaimed reward of `_dataProvider` for `_rewardEpoch` * @param _rewardEpoch reward epoch number * @param _dataProvider address representing the data provider * @return _amount number representing the unclaimed amount * @return _weight number representing the share that has not yet been claimed */ function getUnclaimedReward( uint256 _rewardEpoch, address _dataProvider ) external view returns ( uint256 _amount, uint256 _weight ); }
contracts/userInterfaces/IPriceSubmitter.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../genesis/interface/IFtsoGenesis.sol"; import "../genesis/interface/IFtsoRegistryGenesis.sol"; import "../genesis/interface/IFtsoManagerGenesis.sol"; interface IPriceSubmitter { /** * Event emitted when hash was submitted through PriceSubmitter. * @param submitter the address of the sender * @param epochId current price epoch id * @param hash the submitted hash * @param timestamp current block timestamp */ event HashSubmitted( address indexed submitter, uint256 indexed epochId, bytes32 hash, uint256 timestamp ); /** * Event emitted when prices were revealed through PriceSubmitter. * @param voter the address of the sender * @param epochId id of the epoch in which the price hash was submitted * @param ftsos array of ftsos that correspond to the indexes in the call * @param prices the submitted prices * @param timestamp current block timestamp */ event PricesRevealed( address indexed voter, uint256 indexed epochId, IFtsoGenesis[] ftsos, uint256[] prices, uint256 random, uint256 timestamp ); /** * @notice Submits hash for current epoch * @param _epochId Target epoch id to which hash is submitted * @param _hash Hash of ftso indices, prices, random number and voter address * @notice Emits HashSubmitted event */ function submitHash( uint256 _epochId, bytes32 _hash ) external; /** * @notice Reveals submitted prices during epoch reveal period * @param _epochId Id of the epoch in which the price hashes was submitted * @param _ftsoIndices List of increasing ftso indices * @param _prices List of submitted prices in USD * @param _random Submitted random number * @notice The hash of ftso indices, prices, random number and voter address must be equal to the submitted hash * @notice Emits PricesRevealed event */ function revealPrices( uint256 _epochId, uint256[] memory _ftsoIndices, uint256[] memory _prices, uint256 _random ) external; /** * Returns bitmap of all ftso's for which `_voter` is allowed to submit prices/hashes. * If voter is allowed to vote for ftso at index (see *_FTSO_INDEX), the corrsponding * bit in the result will be 1. */ function voterWhitelistBitmap(address _voter) external view returns (uint256); function getVoterWhitelister() external view returns (address); function getFtsoRegistry() external view returns (IFtsoRegistryGenesis); function getFtsoManager() external view returns (IFtsoManagerGenesis); /** * @notice Returns current random number */ function getCurrentRandom() external view returns (uint256); /** * @notice Returns random number of the specified epoch * @param _epochId Id of the epoch */ function getRandom(uint256 _epochId) external view returns (uint256); }
contracts/userInterfaces/IFtso.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IFtso { enum PriceFinalizationType { // initial state NOT_FINALIZED, // median calculation used to find price WEIGHTED_MEDIAN, // low turnout - price calculated from median of trusted addresses TRUSTED_ADDRESSES, // low turnout + no votes from trusted addresses - price copied from previous epoch PREVIOUS_PRICE_COPIED, // price calculated from median of trusted addresses - triggered due to an exception TRUSTED_ADDRESSES_EXCEPTION, // previous price copied - triggered due to an exception PREVIOUS_PRICE_COPIED_EXCEPTION } event PriceRevealed( address indexed voter, uint256 indexed epochId, uint256 price, uint256 timestamp, uint256 votePowerNat, uint256 votePowerAsset ); event PriceFinalized( uint256 indexed epochId, uint256 price, bool rewardedFtso, uint256 lowRewardPrice, uint256 highRewardPrice, PriceFinalizationType finalizationType, uint256 timestamp ); event PriceEpochInitializedOnFtso( uint256 indexed epochId, uint256 endTime, uint256 timestamp ); event LowTurnout( uint256 indexed epochId, uint256 natTurnout, uint256 lowNatTurnoutThresholdBIPS, uint256 timestamp ); /** * @notice Returns if FTSO is active */ function active() external view returns (bool); /** * @notice Returns the FTSO symbol */ function symbol() external view returns (string memory); /** * @notice Returns current epoch id */ function getCurrentEpochId() external view returns (uint256); /** * @notice Returns id of the epoch which was opened for price submission at the specified timestamp * @param _timestamp Timestamp as seconds from unix epoch */ function getEpochId(uint256 _timestamp) external view returns (uint256); /** * @notice Returns random number of the specified epoch * @param _epochId Id of the epoch */ function getRandom(uint256 _epochId) external view returns (uint256); /** * @notice Returns asset price consented in specific epoch * @param _epochId Id of the epoch * @return Price in USD multiplied by ASSET_PRICE_USD_DECIMALS */ function getEpochPrice(uint256 _epochId) external view returns (uint256); /** * @notice Returns current epoch data * @return _epochId Current epoch id * @return _epochSubmitEndTime End time of the current epoch price submission as seconds from unix epoch * @return _epochRevealEndTime End time of the current epoch price reveal as seconds from unix epoch * @return _votePowerBlock Vote power block for the current epoch * @return _fallbackMode Current epoch in fallback mode - only votes from trusted addresses will be used * @dev half-closed intervals - end time not included */ function getPriceEpochData() external view returns ( uint256 _epochId, uint256 _epochSubmitEndTime, uint256 _epochRevealEndTime, uint256 _votePowerBlock, bool _fallbackMode ); /** * @notice Returns current epoch data * @return _firstEpochStartTs First epoch start timestamp * @return _submitPeriodSeconds Submit period in seconds * @return _revealPeriodSeconds Reveal period in seconds */ function getPriceEpochConfiguration() external view returns ( uint256 _firstEpochStartTs, uint256 _submitPeriodSeconds, uint256 _revealPeriodSeconds ); /** * @notice Returns asset price submitted by voter in specific epoch * @param _epochId Id of the epoch * @param _voter Address of the voter * @return Price in USD multiplied by ASSET_PRICE_USD_DECIMALS */ function getEpochPriceForVoter(uint256 _epochId, address _voter) external view returns (uint256); /** * @notice Returns current asset price * @return _price Price in USD multiplied by ASSET_PRICE_USD_DECIMALS * @return _timestamp Time when price was updated for the last time */ function getCurrentPrice() external view returns (uint256 _price, uint256 _timestamp); /** * @notice Returns current asset price details * @return _price Price in USD multiplied by ASSET_PRICE_USD_DECIMALS * @return _priceTimestamp Time when price was updated for the last time * @return _priceFinalizationType Finalization type when price was updated for the last time * @return _lastPriceEpochFinalizationTimestamp Time when last price epoch was finalized * @return _lastPriceEpochFinalizationType Finalization type of last finalized price epoch */ function getCurrentPriceDetails() external view returns ( uint256 _price, uint256 _priceTimestamp, PriceFinalizationType _priceFinalizationType, uint256 _lastPriceEpochFinalizationTimestamp, PriceFinalizationType _lastPriceEpochFinalizationType ); /** * @notice Returns current random number */ function getCurrentRandom() external view returns (uint256); }
contracts/userInterfaces/IFtsoManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../ftso/interface/IIFtso.sol"; import "../genesis/interface/IFtsoManagerGenesis.sol"; interface IFtsoManager is IFtsoManagerGenesis { event FtsoAdded(IIFtso ftso, bool add); event FallbackMode(bool fallbackMode); event FtsoFallbackMode(IIFtso ftso, bool fallbackMode); event RewardEpochFinalized(uint256 votepowerBlock, uint256 startBlock); event PriceEpochFinalized(address chosenFtso, uint256 rewardEpochId); event InitializingCurrentEpochStateForRevealFailed(IIFtso ftso, uint256 epochId); event FinalizingPriceEpochFailed(IIFtso ftso, uint256 epochId, IFtso.PriceFinalizationType failingType); event DistributingRewardsFailed(address ftso, uint256 epochId); event AccruingUnearnedRewardsFailed(uint256 epochId); function active() external view returns (bool); function getCurrentRewardEpoch() external view returns (uint256); function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view returns (uint256); function getRewardEpochToExpireNext() external view returns (uint256); function getCurrentPriceEpochData() external view returns ( uint256 _priceEpochId, uint256 _priceEpochStartTimestamp, uint256 _priceEpochEndTimestamp, uint256 _priceEpochRevealEndTimestamp, uint256 _currentTimestamp ); function getFtsos() external view returns (IIFtso[] memory _ftsos); function getPriceEpochConfiguration() external view returns ( uint256 _firstPriceEpochStartTs, uint256 _priceEpochDurationSeconds, uint256 _revealEpochDurationSeconds ); function getRewardEpochConfiguration() external view returns ( uint256 _firstRewardEpochStartTs, uint256 _rewardEpochDurationSeconds ); function getFallbackMode() external view returns ( bool _fallbackMode, IIFtso[] memory _ftsos, bool[] memory _ftsoInFallbackMode ); }
contracts/ftso/lib/FtsoManagerSettings.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; /** * @title A library used for Ftso Manager settings management */ library FtsoManagerSettings { struct State { // struct holding settings related to FTSOs // configurable settings uint256 maxVotePowerNatThresholdFraction; // high threshold for native token vote power per voter uint256 maxVotePowerAssetThresholdFraction; // high threshold for asset vote power per voter uint256 lowAssetUSDThreshold; // threshold for low asset vote power (in scaled USD) uint256 highAssetUSDThreshold; // threshold for high asset vote power (in scaled USD) uint256 highAssetTurnoutThresholdBIPS; // threshold for high asset turnout (in BIPS) // actual vote power in (W)NATs / total native token circulating supply (in BIPS) uint256 lowNatTurnoutThresholdBIPS; uint256 rewardExpiryOffsetSeconds; // Reward epoch closed earlier than //block.timestamp - rewardExpiryOffsetSeconds expire address[] trustedAddresses; //trusted addresses will be used as a fallback mechanism for setting the price bool changed; bool initialized; } function _setState ( State storage _state, uint256 _maxVotePowerNatThresholdFraction, uint256 _maxVotePowerAssetThresholdFraction, uint256 _lowAssetUSDThreshold, uint256 _highAssetUSDThreshold, uint256 _highAssetTurnoutThresholdBIPS, uint256 _lowNatTurnoutThresholdBIPS, uint256 _rewardExpiryOffsetSeconds, address[] memory _trustedAddresses ) internal { if (_state.maxVotePowerNatThresholdFraction != _maxVotePowerNatThresholdFraction) { _state.changed = true; _state.maxVotePowerNatThresholdFraction = _maxVotePowerNatThresholdFraction; } if (_state.maxVotePowerAssetThresholdFraction != _maxVotePowerAssetThresholdFraction) { _state.changed = true; _state.maxVotePowerAssetThresholdFraction = _maxVotePowerAssetThresholdFraction; } if (_state.lowAssetUSDThreshold != _lowAssetUSDThreshold) { _state.changed = true; _state.lowAssetUSDThreshold = _lowAssetUSDThreshold; } if (_state.highAssetUSDThreshold != _highAssetUSDThreshold) { _state.changed = true; _state.highAssetUSDThreshold = _highAssetUSDThreshold; } if (_state.highAssetTurnoutThresholdBIPS != _highAssetTurnoutThresholdBIPS) { _state.changed = true; _state.highAssetTurnoutThresholdBIPS = _highAssetTurnoutThresholdBIPS; } if (_state.lowNatTurnoutThresholdBIPS != _lowNatTurnoutThresholdBIPS) { _state.changed = true; _state.lowNatTurnoutThresholdBIPS = _lowNatTurnoutThresholdBIPS; } if (_state.rewardExpiryOffsetSeconds != _rewardExpiryOffsetSeconds) { _state.changed = true; _state.rewardExpiryOffsetSeconds = _rewardExpiryOffsetSeconds; } if (_state.trustedAddresses.length != _trustedAddresses.length) { _state.trustedAddresses = _trustedAddresses; _state.changed = true; } else { for (uint i = 0; i < _trustedAddresses.length; i++) { if (_state.trustedAddresses[i] != _trustedAddresses[i]) { _state.changed = true; _state.trustedAddresses[i] = _trustedAddresses[i]; } } } _state.initialized = true; } }
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/utils/implementation/RevertErrorTracking.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; /** * @title Revert Error Tracking * @notice A contract to track and store revert errors **/ contract RevertErrorTracking { struct RevertedError { uint192 lastErrorBlock; uint64 numErrors; address fromContract; uint64 errorTypeIndex; string errorMessage; } struct LastErrorData { uint192 totalRevertedErrors; uint64 lastErrorTypeIndex; } string internal constant INDEX_TOO_HIGH = "start index high"; mapping(bytes32 => RevertedError) internal revertedErrors; bytes32 [] internal revertErrorHashes; LastErrorData public errorData; event ContractRevertError(address theContract, uint256 atBlock, string theMessage); /** * @notice Returns latest reverted error * @return _lastErrorBlock Block number of last reverted error * @return _numErrors Number of times same error with same contract address has been reverted * @return _errorString Revert error message * @return _erroringContract Array of addresses of the reverting contracts * @return _totalRevertedErrors Total number of revert errors across all contracts */ function showLastRevertedError () external view returns( uint256[] memory _lastErrorBlock, uint256[] memory _numErrors, string[] memory _errorString, address[] memory _erroringContract, uint256 _totalRevertedErrors ) { return showRevertedErrors(errorData.lastErrorTypeIndex, 1); } /** * @notice Adds caught error to reverted errors mapping * @param revertedContract Address of the reverting contract * @param message Reverte message */ function addRevertError(address revertedContract, string memory message) internal { bytes32 errorStringHash = keccak256(abi.encode(revertedContract, message)); revertedErrors[errorStringHash].numErrors += 1; revertedErrors[errorStringHash].lastErrorBlock = uint192(block.number); emit ContractRevertError(revertedContract, block.number, message); errorData.totalRevertedErrors += 1; if (revertedErrors[errorStringHash].numErrors > 1) { // not first time this errors return; } // first time we recieve this error string. revertErrorHashes.push(errorStringHash); revertedErrors[errorStringHash].fromContract = revertedContract; revertedErrors[errorStringHash].errorMessage = message; revertedErrors[errorStringHash].errorTypeIndex = uint64(revertErrorHashes.length - 1); errorData.lastErrorTypeIndex = revertedErrors[errorStringHash].errorTypeIndex; } /** * @notice Returns latest reverted error * @param startIndex Starting index in the error list array * @param numErrorTypesToShow Number of error types to show * @return _lastErrorBlock Array of last block number this error reverted * @return _numErrors Number of times the same error with same contract address has been tracked * @return _errorString Array of revert error messages * @return _erroringContract Array of addresses of the reverting contracts * @return _totalRevertedErrors Total number of errors reverted across all contracts */ function showRevertedErrors (uint startIndex, uint numErrorTypesToShow) public view returns( uint256[] memory _lastErrorBlock, uint256[] memory _numErrors, string[] memory _errorString, address[] memory _erroringContract, uint256 _totalRevertedErrors ) { require(startIndex < revertErrorHashes.length, INDEX_TOO_HIGH); uint256 numReportElements = revertErrorHashes.length >= startIndex + numErrorTypesToShow ? numErrorTypesToShow : revertErrorHashes.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 = revertErrorHashes[startIndex + i]; _lastErrorBlock[i] = revertedErrors[hash].lastErrorBlock; _numErrors[i] = revertedErrors[hash].numErrors; _errorString[i] = revertedErrors[hash].errorMessage; _erroringContract[i] = revertedErrors[hash].fromContract; } _totalRevertedErrors = errorData.totalRevertedErrors; } }
contracts/token/interface/IICleanable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IICleanable { /** * Set the contract that is allowed to call history cleaning methods. */ function setCleanerContract(address _cleanerContract) external; /** * Set the cleanup block number. * Historic data for the blocks before `cleanupBlockNumber` can be erased, * history before that block should never be used since it can be inconsistent. * In particular, cleanup block number must be before current vote power block. * @param _blockNumber The new cleanup block number. */ function setCleanupBlockNumber(uint256 _blockNumber) external; /** * Get the current cleanup block number. */ function cleanupBlockNumber() external view returns (uint256); }
contracts/genesis/interface/IFtsoRegistryGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "./IFtsoGenesis.sol"; interface IFtsoRegistryGenesis { function getFtsos(uint256[] memory _indices) external view returns(IFtsoGenesis[] memory _ftsos); }
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/utils/interface/IUpdateValidators.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IUpdateValidators { /** update the validators after reward epoch **/ function updateActiveValidators() external; }
contracts/userInterfaces/IFtsoRegistry.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; import "../ftso/interface/IIFtso.sol"; import "../genesis/interface/IFtsoRegistryGenesis.sol"; interface IFtsoRegistry is IFtsoRegistryGenesis { function getFtso(uint256 _ftsoIndex) external view returns(IIFtso _activeFtsoAddress); function getFtsoBySymbol(string memory _symbol) external view returns(IIFtso _activeFtsoAddress); function getSupportedIndices() external view returns(uint256[] memory _supportedIndices); function getSupportedSymbols() external view returns(string[] memory _supportedSymbols); function getSupportedFtsos() external view returns(IIFtso[] memory _ftsos); function getFtsoIndex(string memory _symbol) external view returns (uint256 _assetIndex); function getFtsoSymbol(uint256 _ftsoIndex) external view returns (string memory _symbol); function getCurrentPrice(uint256 _ftsoIndex) external view returns(uint256 _price, uint256 _timestamp); function getCurrentPrice(string memory _symbol) external view returns(uint256 _price, uint256 _timestamp); function getSupportedIndicesAndFtsos() external view returns(uint256[] memory _supportedIndices, IIFtso[] memory _ftsos); function getSupportedSymbolsAndFtsos() external view returns(string[] memory _supportedSymbols, IIFtso[] memory _ftsos); function getSupportedIndicesAndSymbols() external view returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols); function getSupportedIndicesSymbolsAndFtsos() external view returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols, IIFtso[] memory _ftsos); }
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/IVoterWhitelister.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IVoterWhitelister { /** * Raised when an account is removed from the voter whitelist. */ event VoterWhitelisted(address voter, uint256 ftsoIndex); /** * Raised when an account is removed from the voter whitelist. */ event VoterRemovedFromWhitelist(address voter, uint256 ftsoIndex); /** * Request to whitelist `_voter` account to ftso at `_ftsoIndex`. Will revert if vote power too low. * May be called by any address. */ function requestWhitelistingVoter(address _voter, uint256 _ftsoIndex) external; /** * Request to whitelist `_voter` account to all active ftsos. * May be called by any address. * It returns an array of supported ftso indices and success flag per index. */ function requestFullVoterWhitelisting( address _voter ) external returns ( uint256[] memory _supportedIndices, bool[] memory _success ); /** * Maximum number of voters in the whitelist for a new FTSO. */ function defaultMaxVotersForFtso() external view returns (uint256); /** * Maximum number of voters in the whitelist for FTSO at index `_ftsoIndex`. */ function maxVotersForFtso(uint256 _ftsoIndex) external view returns (uint256); /** * Get whitelisted price providers for ftso with `_symbol` */ function getFtsoWhitelistedPriceProvidersBySymbol(string memory _symbol) external view returns (address[] memory); /** * Get whitelisted price providers for ftso at `_ftsoIndex` */ function getFtsoWhitelistedPriceProviders(uint256 _ftsoIndex) external view returns (address[] memory); }
contracts/token/interface/IIVPContract.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IVPToken.sol"; import "../../userInterfaces/IVPContractEvents.sol"; import "./IICleanable.sol"; interface IIVPContract is IICleanable, IVPContractEvents { /** * Update vote powers when tokens are transfered. * Also update delegated vote powers for percentage delegation * and check for enough funds for explicit delegations. **/ function updateAtTokenTransfer( address _from, address _to, uint256 _fromBalance, uint256 _toBalance, uint256 _amount ) external; /** * @notice Delegate `_bips` percentage of voting power to `_to` from `_from` * @param _from The address of the delegator * @param _to The address of the recipient * @param _balance The delegator's current balance * @param _bips The percentage of voting power to be delegated expressed in basis points (1/100 of one percent). * Not cummulative - every call resets the delegation value (and value of 0 revokes delegation). **/ function delegate( address _from, address _to, uint256 _balance, uint256 _bips ) external; /** * @notice Explicitly delegate `_amount` of voting power to `_to` from `msg.sender`. * @param _from The address of the delegator * @param _to The address of the recipient * @param _balance The delegator's current balance * @param _amount An explicit vote power amount to be delegated. * Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`). **/ function delegateExplicit( address _from, address _to, uint256 _balance, uint _amount ) external; /** * @notice Revoke all delegation from sender to `_who` at given block. * Only affects the reads via `votePowerOfAtCached()` in the block `_blockNumber`. * Block `_blockNumber` must be in the past. * This method should be used only to prevent rogue delegate voting in the current voting block. * To stop delegating use delegate/delegateExplicit with value of 0 or undelegateAll/undelegateAllExplicit. * @param _from The address of the delegator * @param _who Address of the delegatee * @param _balance The delegator's current balance * @param _blockNumber The block number at which to revoke delegation. **/ function revokeDelegationAt( address _from, address _who, uint256 _balance, uint _blockNumber ) external; /** * @notice Undelegate all voting power for delegates of `msg.sender` * Can only be used with percentage delegation. * Does not reset delegation mode back to NOTSET. * @param _from The address of the delegator **/ function undelegateAll( address _from, uint256 _balance ) external; /** * @notice Undelegate all explicit vote power by amount delegates for `msg.sender`. * Can only be used with explicit delegation. * Does not reset delegation mode back to NOTSET. * @param _from The address of the delegator * @param _delegateAddresses Explicit delegation does not store delegatees' addresses, * so the caller must supply them. * @return The amount still delegated (in case the list of delegates was incomplete). */ function undelegateAllExplicit( address _from, address[] memory _delegateAddresses ) external returns (uint256); /** * @notice Get the vote power of `_who` at block `_blockNumber` * Reads/updates cache and upholds revocations. * @param _who The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_who` at `_blockNumber`. */ function votePowerOfAtCached(address _who, uint256 _blockNumber) external returns(uint256); /** * @notice Get the current vote power of `_who`. * @param _who The address to get voting power. * @return Current vote power of `_who`. */ function votePowerOf(address _who) external view returns(uint256); /** * @notice Get the vote power of `_who` at block `_blockNumber` * @param _who The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_who` at `_blockNumber`. */ function votePowerOfAt(address _who, uint256 _blockNumber) external view returns(uint256); /** * @notice Get the vote power of `_who` at block `_blockNumber`, ignoring revocation information (and cache). * @param _who The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_who` at `_blockNumber`. Result doesn't change if vote power is revoked. */ function votePowerOfAtIgnoringRevocation(address _who, uint256 _blockNumber) external view returns(uint256); /** * Return vote powers for several addresses in a batch. * @param _owners The list of addresses to fetch vote power of. * @param _blockNumber The block number at which to fetch. * @return A list of vote powers. */ function batchVotePowerOfAt( address[] memory _owners, uint256 _blockNumber ) external view returns(uint256[] memory); /** * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee. * @param _from Address of delegator * @param _to Address of delegatee * @param _balance The delegator's current balance * @return The delegated vote power. */ function votePowerFromTo( address _from, address _to, uint256 _balance ) external view returns(uint256); /** * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`. * @param _from Address of delegator * @param _to Address of delegatee * @param _balance The delegator's current balance * @param _blockNumber The block number at which to fetch. * @return The delegated vote power. */ function votePowerFromToAt( address _from, address _to, uint256 _balance, uint _blockNumber ) external view returns(uint256); /** * @notice Compute the current undelegated vote power of `_owner` * @param _owner The address to get undelegated voting power. * @param _balance Owner's current balance * @return The unallocated vote power of `_owner` */ function undelegatedVotePowerOf( address _owner, uint256 _balance ) external view returns(uint256); /** * @notice Get the undelegated vote power of `_owner` at given block. * @param _owner The address to get undelegated voting power. * @param _blockNumber The block number at which to fetch. * @return The undelegated vote power of `_owner` (= owner's own balance minus all delegations from owner) */ function undelegatedVotePowerOfAt( address _owner, uint256 _balance, uint256 _blockNumber ) external view returns(uint256); /** * @notice Get the delegation mode for '_who'. This mode determines whether vote power is * allocated by percentage or by explicit value. * @param _who The address to get delegation mode. * @return Delegation mode (NOTSET=0, PERCENTAGE=1, AMOUNT=2)) */ function delegationModeOf(address _who) external view returns (uint256); /** * @notice Get the vote power delegation `_delegateAddresses` * and `pcts` of an `_owner`. Returned in two separate positional arrays. * @param _owner The address to get delegations. * @return _delegateAddresses Positional array of delegation addresses. * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent) * @return _count The number of delegates. * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2). */ function delegatesOf( address _owner ) external view returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ); /** * @notice Get the vote power delegation `delegationAddresses` * and `pcts` of an `_owner`. Returned in two separate positional arrays. * @param _owner The address to get delegations. * @param _blockNumber The block for which we want to know the delegations. * @return _delegateAddresses Positional array of delegation addresses. * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent) * @return _count The number of delegates. * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2). */ function delegatesOfAt( address _owner, uint256 _blockNumber ) external view returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ); /** * The VPToken (or some other contract) that owns this VPContract. * All state changing methods may be called only from this address. * This is because original msg.sender is sent in `_from` parameter * and we must be sure that it cannot be faked by directly calling VPContract. * Owner token is also used in case of replacement to recover vote powers from balances. */ function ownerToken() external view returns (IVPToken); /** * Return true if this IIVPContract is configured to be used as a replacement for other contract. * It means that vote powers are not necessarily correct at the initialization, therefore * every method that reads vote power must check whether it is initialized for that address and block. */ function isReplacement() external view returns (bool); }
contracts/utils/implementation/GovernedAndFlareDaemonized.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import { FlareDaemon } from "../../genesis/implementation/FlareDaemon.sol"; import { Governed } from "../../governance/implementation/Governed.sol"; contract GovernedAndFlareDaemonized is Governed { FlareDaemon public immutable flareDaemon; modifier onlyFlareDaemon () { require (msg.sender == address(flareDaemon), "only flare daemon"); _; } constructor(address _governance, FlareDaemon _flareDaemon) Governed(_governance) { require(address(_flareDaemon) != address(0), "flare daemon zero"); flareDaemon = _flareDaemon; } }
@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; } }
contracts/ftso/interface/IIFtso.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../genesis/interface/IFtsoGenesis.sol"; import "../../userInterfaces/IFtso.sol"; import "../../token/interface/IIVPToken.sol"; interface IIFtso is IFtso, IFtsoGenesis { /// function finalizePriceReveal /// called by reward manager only on correct timing. /// if price reveal period for epoch x ended. finalize. /// iterate list of price submissions /// find weighted median /// find adjucant 50% of price submissions. /// Allocate reward for any price submission which is same as a "winning" submission function finalizePriceEpoch(uint256 _epochId, bool _returnRewardData) external returns( address[] memory _eligibleAddresses, uint256[] memory _natWeights, uint256 _totalNatWeight ); function fallbackFinalizePriceEpoch(uint256 _epochId) external; function forceFinalizePriceEpoch(uint256 _epochId) external; // activateFtso will be called by ftso manager once ftso is added // before this is done, FTSO can't run function activateFtso( uint256 _firstEpochStartTs, uint256 _submitPeriodSeconds, uint256 _revealPeriodSeconds ) external; function deactivateFtso() external; // update initial price and timestamp - only if not active function updateInitialPrice(uint256 _initialPriceUSD, uint256 _initialPriceTimestamp) external; function configureEpochs( uint256 _maxVotePowerNatThresholdFraction, uint256 _maxVotePowerAssetThresholdFraction, uint256 _lowAssetUSDThreshold, uint256 _highAssetUSDThreshold, uint256 _highAssetTurnoutThresholdBIPS, uint256 _lowNatTurnoutThresholdBIPS, address[] memory _trustedAddresses ) external; function setAsset(IIVPToken _asset) external; function setAssetFtsos(IIFtso[] memory _assetFtsos) external; // current vote power block will update per reward epoch. // the FTSO doesn't have notion of reward epochs. // reward manager only can set this data. function setVotePowerBlock(uint256 _blockNumber) external; function initializeCurrentEpochStateForReveal(uint256 _circulatingSupplyNat, bool _fallbackMode) external; /** * @notice Returns ftso manager address */ function ftsoManager() external view returns (address); /** * @notice Returns the FTSO asset * @dev Asset is null in case of multi-asset FTSO */ function getAsset() external view returns (IIVPToken); /** * @notice Returns the Asset FTSOs * @dev AssetFtsos is not null only in case of multi-asset FTSO */ function getAssetFtsos() external view returns (IIFtso[] memory); /** * @notice Returns current configuration of epoch state * @return _maxVotePowerNatThresholdFraction High threshold for native token vote power per voter * @return _maxVotePowerAssetThresholdFraction High threshold for asset vote power per voter * @return _lowAssetUSDThreshold Threshold for low asset vote power * @return _highAssetUSDThreshold Threshold for high asset vote power * @return _highAssetTurnoutThresholdBIPS Threshold for high asset turnout * @return _lowNatTurnoutThresholdBIPS Threshold for low nat turnout * @return _trustedAddresses Trusted addresses - use their prices if low nat turnout is not achieved */ function epochsConfiguration() external view returns ( uint256 _maxVotePowerNatThresholdFraction, uint256 _maxVotePowerAssetThresholdFraction, uint256 _lowAssetUSDThreshold, uint256 _highAssetUSDThreshold, uint256 _highAssetTurnoutThresholdBIPS, uint256 _lowNatTurnoutThresholdBIPS, address[] memory _trustedAddresses ); /** * @notice Returns parameters necessary for approximately replicating vote weighting. * @return _assets the list of Assets that are accounted in vote * @return _assetMultipliers weight of each asset in (multiasset) ftso, mutiplied by TERA * @return _totalVotePowerNat total native token vote power at block * @return _totalVotePowerAsset total combined asset vote power at block * @return _assetWeightRatio ratio of combined asset vp vs. native token vp (in BIPS) * @return _votePowerBlock vote powewr block for given epoch */ function getVoteWeightingParameters() external view returns ( IIVPToken[] memory _assets, uint256[] memory _assetMultipliers, uint256 _totalVotePowerNat, uint256 _totalVotePowerAsset, uint256 _assetWeightRatio, uint256 _votePowerBlock ); function wNat() external view returns (IIVPToken); /** * @notice Returns current asset price calculated from trusted providers * @return _price Price in USD multiplied by ASSET_PRICE_USD_DECIMALS * @return _timestamp Time when price was updated for the last time */ function getCurrentPriceFromTrustedProviders() external view returns (uint256 _price, uint256 _timestamp); }
contracts/ftso/interface/IIFtsoManagerV1.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; // interface for the first version of ftso manger (V1 = oldest version) - last version is always without any Vx interface IIFtsoManagerV1 { function rewardEpochsStartTs() external view returns(uint256); function rewardEpochDurationSeconds() external view returns(uint256); function getCurrentRewardEpoch() external view returns(uint256); function rewardEpochs(uint256 _rewardEpochId) external view returns ( uint256 _votepowerBlock, uint256 _startBlock, uint256 _startTimestamp ); function getPriceEpochConfiguration() external view returns ( uint256 _firstPriceEpochStartTs, uint256 _priceEpochDurationSeconds, uint256 _revealEpochDurationSeconds ); }
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/utils/interface/IIFtsoRegistry.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; import "../../ftso/interface/IIFtso.sol"; import "../../userInterfaces/IFtsoRegistry.sol"; interface IIFtsoRegistry is IFtsoRegistry { // returns ftso index function addFtso(IIFtso _ftsoContract) external returns(uint256); function removeFtso(IIFtso _ftso) external; }
contracts/userInterfaces/IFtsoRewardManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IFtsoRewardManager { event RewardClaimed( address indexed dataProvider, address indexed whoClaimed, address indexed sentTo, uint256 rewardEpoch, uint256 amount ); event UnearnedRewardsAccrued( uint256 epochId, uint256 reward ); event RewardsDistributed( address indexed ftso, uint256 epochId, address[] addresses, uint256[] rewards ); event RewardClaimsEnabled( uint256 rewardEpochId ); event FeePercentageChanged( address indexed dataProvider, uint256 value, uint256 validFromEpoch ); event RewardClaimsExpired( uint256 rewardEpochId ); event ClaimExecutorsChanged( address rewardOwner, address[] executors ); event AllowedClaimRecipientsChanged( address rewardOwner, address[] recipients ); /** * @notice Allows a percentage delegator to claim rewards. * @notice This function is intended to be used to claim rewards in case of delegation by percentage. * @param _recipient address to transfer funds to * @param _rewardEpochs array of reward epoch numbers to claim for * @return _rewardAmount amount of total claimed rewards * @dev Reverts if `msg.sender` is delegating by amount */ function claimReward(address payable _recipient, uint256[] memory _rewardEpochs) external returns (uint256 _rewardAmount); /** * @notice Allows a percentage delegator to claim and wrap rewards. * @notice This function is intended to be used to claim and wrap rewards in case of delegation by percentage. * @param _recipient address to transfer funds to * @param _rewardEpochs array of reward epoch numbers to claim for * @return _rewardAmount amount of total claimed rewards * @dev Reverts if `msg.sender` is delegating by amount */ function claimAndWrapReward(address payable _recipient, uint256[] memory _rewardEpochs) external returns (uint256 _rewardAmount); /** * @notice Allows a percentage delegator to claim and wrap rewards. * @notice This function is intended to be used to claim and wrap rewards in case of delegation by percentage. * @notice The caller does not have to be the owner, but must be approved by the owner to claim on his behalf. * this approval is done by calling `addClaimExecutor`. * @notice It is actually safe for this to be called by anybody (nothing can be stolen), but by limiting who can * call, we allow the owner to control the timing of the calls. * @param _rewardOwner address of the reward owner * @param _recipient address of the recipient; must be either _rewardOwner or one of the addresses * allowed by the _rewardOwner * @param _rewardEpochs array of reward epoch numbers to claim for * @return _rewardAmount amount of total claimed rewards * @dev Reverts if `msg.sender` is delegating by amount */ function claimAndWrapRewardByExecutor( address _rewardOwner, address payable _recipient, uint256[] memory _rewardEpochs ) external returns (uint256 _rewardAmount); /** * @notice Allows the sender to claim rewards from specified data providers. * @notice This function is intended to be used to claim rewards in case of delegation by amount. * @param _recipient address to transfer funds to * @param _rewardEpochs array of reward epoch numbers to claim for * @param _dataProviders array of addresses representing data providers to claim the reward from * @return _rewardAmount amount of total claimed rewards * @dev Function can be used by a percentage delegator but is more gas consuming than `claimReward`. */ function claimRewardFromDataProviders( address payable _recipient, uint256[] memory _rewardEpochs, address[] memory _dataProviders ) external returns (uint256 _rewardAmount); /** * @notice Allows the sender to claim and wrap rewards from specified data providers. * @notice This function is intended to be used to claim and wrap rewards in case of delegation by amount. * @param _recipient address to transfer funds to * @param _rewardEpochs array of reward epoch numbers to claim for * @param _dataProviders array of addresses representing data providers to claim the reward from * @return _rewardAmount amount of total claimed rewards * @dev Function can be used by a percentage delegator but is more gas consuming than `claimReward`. */ function claimAndWrapRewardFromDataProviders( address payable _recipient, uint256[] memory _rewardEpochs, address[] memory _dataProviders ) external returns (uint256 _rewardAmount); /** * @notice Allows the sender to claim and wrap rewards from specified data providers. * @notice This function is intended to be used to claim and wrap rewards in case of delegation by amount. * @notice The caller does not have to be the owner, but must be approved by the owner to claim on his behalf. * this approval is done by calling `addClaimExecutor`. * @notice It is actually safe for this to be called by anybody (nothing can be stolen), but by limiting who can * call, we allow the owner to control the timing of the calls. * @param _rewardOwner address of the reward owner * @param _recipient address of the recipient; must be either _rewardOwner or one of the addresses * allowed by the _rewardOwner * @param _rewardEpochs array of reward epoch numbers to claim for * @param _dataProviders array of addresses representing data providers to claim the reward from * @return _rewardAmount amount of total claimed rewards * @dev Function can be used by a percentage delegator but is more gas consuming than `claimReward`. */ function claimAndWrapRewardFromDataProvidersByExecutor( address _rewardOwner, address payable _recipient, uint256[] memory _rewardEpochs, address[] memory _dataProviders ) external returns (uint256 _rewardAmount); /** * Set the addresses of executors, who are allowed to call claimAndWrapRewardByExecutor * and claimAndWrapRewardFromDataProvidersByExecutor. * @param _executors The new executors. All old executors will be deleted and replaced by these. */ function setClaimExecutors(address[] memory _executors) external; /** * Set the addresses of allowed recipients in the methods claimAndWrapRewardByExecutor * and claimAndWrapRewardFromDataProvidersByExecutor. * Apart from these, the reward owner is always an allowed recipient. * @param _recipients The new allowed recipients. All old recipients will be deleted and replaced by these. */ function setAllowedClaimRecipients(address[] memory _recipients) external; /** * @notice Allows data provider to set (or update last) fee percentage. * @param _feePercentageBIPS number representing fee percentage in BIPS * @return _validFromEpoch reward epoch number when the setting becomes effective. */ function setDataProviderFeePercentage(uint256 _feePercentageBIPS) external returns (uint256 _validFromEpoch); /** * @notice Allows reward claiming */ function active() external view returns (bool); /** * @notice Returns the current fee percentage of `_dataProvider` * @param _dataProvider address representing data provider */ function getDataProviderCurrentFeePercentage(address _dataProvider) external view returns (uint256 _feePercentageBIPS); /** * @notice Returns the fee percentage of `_dataProvider` at `_rewardEpoch` * @param _dataProvider address representing data provider * @param _rewardEpoch reward epoch number */ function getDataProviderFeePercentage( address _dataProvider, uint256 _rewardEpoch ) external view returns (uint256 _feePercentageBIPS); /** * @notice Returns the scheduled fee percentage changes of `_dataProvider` * @param _dataProvider address representing data provider * @return _feePercentageBIPS positional array of fee percentages in BIPS * @return _validFromEpoch positional array of block numbers the fee setings are effective from * @return _fixed positional array of boolean values indicating if settings are subjected to change */ function getDataProviderScheduledFeePercentageChanges(address _dataProvider) external view returns ( uint256[] memory _feePercentageBIPS, uint256[] memory _validFromEpoch, bool[] memory _fixed ); /** * @notice Returns information on epoch reward * @param _rewardEpoch reward epoch number * @return _totalReward number representing the total epoch reward * @return _claimedReward number representing the amount of total epoch reward that has been claimed */ function getEpochReward(uint256 _rewardEpoch) external view returns (uint256 _totalReward, uint256 _claimedReward); /** * @notice Returns the state of rewards for `_beneficiary` at `_rewardEpoch` * @param _beneficiary address of reward beneficiary * @param _rewardEpoch reward epoch number * @return _dataProviders positional array of addresses representing data providers * @return _rewardAmounts positional array of reward amounts * @return _claimed positional array of boolean values indicating if reward is claimed * @return _claimable boolean value indicating if rewards are claimable * @dev Reverts when queried with `_beneficary` delegating by amount */ function getStateOfRewards( address _beneficiary, uint256 _rewardEpoch ) external view returns ( address[] memory _dataProviders, uint256[] memory _rewardAmounts, bool[] memory _claimed, bool _claimable ); /** * @notice Returns the state of rewards for `_beneficiary` at `_rewardEpoch` from `_dataProviders` * @param _beneficiary address of reward beneficiary * @param _rewardEpoch reward epoch number * @param _dataProviders positional array of addresses representing data providers * @return _rewardAmounts positional array of reward amounts * @return _claimed positional array of boolean values indicating if reward is claimed * @return _claimable boolean value indicating if rewards are claimable */ function getStateOfRewardsFromDataProviders( address _beneficiary, uint256 _rewardEpoch, address[] memory _dataProviders ) external view returns ( uint256[] memory _rewardAmounts, bool[] memory _claimed, bool _claimable ); /** * @notice Returns the start and the end of the reward epoch range for which the reward is claimable * @param _startEpochId the oldest epoch id that allows reward claiming * @param _endEpochId the newest epoch id that allows reward claiming */ function getEpochsWithClaimableRewards() external view returns ( uint256 _startEpochId, uint256 _endEpochId ); /** * @notice Returns the array of claimable epoch ids for which the reward has not yet been claimed * @param _beneficiary address of reward beneficiary * @return _epochIds array of epoch ids * @dev Reverts when queried with `_beneficary` delegating by amount */ function getEpochsWithUnclaimedRewards(address _beneficiary) external view returns ( uint256[] memory _epochIds ); /** * @notice Returns the information on claimed reward of `_dataProvider` for `_rewardEpoch` by `_claimer` * @param _rewardEpoch reward epoch number * @param _dataProvider address representing the data provider * @param _claimer address representing the claimer * @return _claimed boolean indicating if reward has been claimed * @return _amount number representing the claimed amount */ function getClaimedReward( uint256 _rewardEpoch, address _dataProvider, address _claimer ) external view returns ( bool _claimed, uint256 _amount ); /** * @notice Return reward epoch that will expire, when new reward epoch will start * @return Reward epoch id that will expire next */ function getRewardEpochToExpireNext() external view returns (uint256); /** * @notice Return reward epoch vote power block * @param _rewardEpoch reward epoch number */ function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view returns (uint256); /** * @notice Return current reward epoch number */ function getCurrentRewardEpoch() external view returns (uint256); /** * @notice Return initial reward epoch number */ function getInitialRewardEpoch() external view returns (uint256); /** * @notice Returns the information on rewards and initial vote power of `_dataProvider` for `_rewardEpoch` * @param _rewardEpoch reward epoch number * @param _dataProvider address representing the data provider * @return _rewardAmount number representing the amount of rewards * @return _votePowerIgnoringRevocation number representing the vote power ignoring revocations */ function getDataProviderPerformanceInfo( uint256 _rewardEpoch, address _dataProvider ) external view returns ( uint256 _rewardAmount, uint256 _votePowerIgnoringRevocation ); /** * Get the addresses of executors, who are allowed to call claimAndWrapRewardByExecutor * and claimAndWrapRewardFromDataProvidersByExecutor. */ function claimExecutors(address _rewardOwner) external view returns (address[] memory); /** * Get the addresses of allowed recipients in the methods claimAndWrapRewardByExecutor * and claimAndWrapRewardFromDataProvidersByExecutor. * Apart from these, the reward owner is always an allowed recipient. */ function allowedClaimRecipients(address _rewardOwner) external view returns (address[] memory); }
contracts/addressUpdater/implementation/AddressUpdatable.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../interface/IIAddressUpdatable.sol"; abstract contract AddressUpdatable is IIAddressUpdatable { // https://docs.soliditylang.org/en/v0.8.7/contracts.html#constant-and-immutable-state-variables // No storage slot is allocated bytes32 internal constant ADDRESS_STORAGE_POSITION = keccak256("flare.diamond.AddressUpdatable.ADDRESS_STORAGE_POSITION"); modifier onlyAddressUpdater() { require (msg.sender == getAddressUpdater(), "only address updater"); _; } constructor(address _addressUpdater) { setAddressUpdaterValue(_addressUpdater); } function getAddressUpdater() public view returns (address _addressUpdater) { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { _addressUpdater := sload(position) } } /** * @notice external method called from AddressUpdater only */ function updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) external override onlyAddressUpdater { // update addressUpdater address setAddressUpdaterValue(_getContractAddress(_contractNameHashes, _contractAddresses, "AddressUpdater")); // update all other addresses _updateContractAddresses(_contractNameHashes, _contractAddresses); } /** * @notice virtual method that a contract extending AddressUpdatable must implement */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal virtual; /** * @notice helper method to get contract address * @dev it reverts if contract name does not exist */ function _getContractAddress( bytes32[] memory _nameHashes, address[] memory _addresses, string memory _nameToFind ) internal pure returns(address) { bytes32 nameHash = keccak256(abi.encode(_nameToFind)); address a = address(0); for (uint256 i = 0; i < _nameHashes.length; i++) { if (nameHash == _nameHashes[i]) { a = _addresses[i]; break; } } require(a != address(0), "address zero"); return a; } function setAddressUpdaterValue(address _addressUpdater) internal { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { sstore(position, _addressUpdater) } } }
contracts/genesis/interface/IFtsoGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IFtsoGenesis { /** * @notice Reveals submitted price during epoch reveal period - only price submitter * @param _voter Voter address * @param _epochId Id of the epoch in which the price hash was submitted * @param _price Submitted price in USD * @notice The hash of _price and _random must be equal to the submitted hash * @notice Emits PriceRevealed event */ function revealPriceSubmitter( address _voter, uint256 _epochId, uint256 _price, uint256 _wNatVP ) external; /** * @notice Get (and cache) wNat vote power for specified voter and given epoch id * @param _voter Voter address * @param _epochId Id of the epoch in which the price hash was submitted * @return wNat vote power */ function wNatVotePowerCached(address _voter, uint256 _epochId) external returns (uint256); }
contracts/token/interface/IIVPToken.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IVPToken.sol"; import "../../userInterfaces/IGovernanceVotePower.sol"; import "./IIVPContract.sol"; import "./IIGovernanceVotePower.sol"; import "./IICleanable.sol"; interface IIVPToken is IVPToken, IICleanable { /** * Set the contract that is allowed to set cleanupBlockNumber. * Usually this will be an instance of CleanupBlockNumberManager. */ function setCleanupBlockNumberManager(address _cleanupBlockNumberManager) external; /** * Sets new governance vote power contract that allows token owners to participate in governance voting * and delegate governance vote power. */ function setGovernanceVotePower(IIGovernanceVotePower _governanceVotePower) external; /** * @notice Get the total vote power at block `_blockNumber` using cache. * It tries to read the cached value and if not found, reads the actual value and stores it in cache. * Can only be used if `_blockNumber` is in the past, otherwise reverts. * @param _blockNumber The block number at which to fetch. * @return The total vote power at the block (sum of all accounts' vote powers). */ function totalVotePowerAtCached(uint256 _blockNumber) external returns(uint256); /** * @notice Get the vote power of `_owner` at block `_blockNumber` using cache. * It tries to read the cached value and if not found, reads the actual value and stores it in cache. * Can only be used if _blockNumber is in the past, otherwise reverts. * @param _owner The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_owner` at `_blockNumber`. */ function votePowerOfAtCached(address _owner, uint256 _blockNumber) external returns(uint256); /** * Return vote powers for several addresses in a batch. * @param _owners The list of addresses to fetch vote power of. * @param _blockNumber The block number at which to fetch. * @return A list of vote powers. */ function batchVotePowerOfAt( address[] memory _owners, uint256 _blockNumber ) external view returns(uint256[] memory); }
contracts/genesis/interface/IFtsoManagerGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IFtsoManagerGenesis { function getCurrentPriceEpochId() external view returns (uint256 _priceEpochId); }
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/userInterfaces/IGovernanceVotePower.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IGovernanceVotePower { /** * @notice Delegate all governance vote power of `msg.sender` to `_to`. * @param _to The address of the recipient **/ function delegate(address _to) external; /** * @notice Undelegate all governance vote power of `msg.sender``. **/ function undelegate() external; /** * @notice Get the governance vote power of `_who` at block `_blockNumber` * @param _who The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return _votePower Governance vote power of `_who` at `_blockNumber`. */ function votePowerOfAt(address _who, uint256 _blockNumber) external view returns(uint256); /** * @notice Get the vote power of `account` at the current block. * @param account The address to get voting power. * @return Vote power of `account` at the current block number. */ function getVotes(address account) external view returns (uint256); /** * @notice Get the delegate's address of `_who` at block `_blockNumber` * @param _who The address to get delegate's address. * @param _blockNumber The block number at which to fetch. * @return Delegate's address of `_who` at `_blockNumber`. */ function getDelegateOfAt(address _who, uint256 _blockNumber) external view returns (address); /** * @notice Get the delegate's address of `_who` at the current block. * @param _who The address to get delegate's address. * @return Delegate's address of `_who` at the current block number. */ function getDelegateOfAtNow(address _who) external view returns (address); }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
contracts/userInterfaces/IVPToken.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IGovernanceVotePower} from "./IGovernanceVotePower.sol"; import {IVPContractEvents} from "./IVPContractEvents.sol"; interface IVPToken is IERC20 { /** * @notice Delegate by percentage `_bips` of voting power to `_to` from `msg.sender`. * @param _to The address of the recipient * @param _bips The percentage of voting power to be delegated expressed in basis points (1/100 of one percent). * Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`). **/ function delegate(address _to, uint256 _bips) external; /** * @notice Undelegate all percentage delegations from teh sender and then delegate corresponding * `_bips` percentage of voting power from the sender to each member of `_delegatees`. * @param _delegatees The addresses of the new recipients. * @param _bips The percentages of voting power to be delegated expressed in basis points (1/100 of one percent). * Total of all `_bips` values must be at most 10000. **/ function batchDelegate(address[] memory _delegatees, uint256[] memory _bips) external; /** * @notice Explicitly delegate `_amount` of voting power to `_to` from `msg.sender`. * @param _to The address of the recipient * @param _amount An explicit vote power amount to be delegated. * Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`). **/ function delegateExplicit(address _to, uint _amount) external; /** * @notice Revoke all delegation from sender to `_who` at given block. * Only affects the reads via `votePowerOfAtCached()` in the block `_blockNumber`. * Block `_blockNumber` must be in the past. * This method should be used only to prevent rogue delegate voting in the current voting block. * To stop delegating use delegate/delegateExplicit with value of 0 or undelegateAll/undelegateAllExplicit. * @param _who Address of the delegatee * @param _blockNumber The block number at which to revoke delegation. */ function revokeDelegationAt(address _who, uint _blockNumber) external; /** * @notice Undelegate all voting power for delegates of `msg.sender` * Can only be used with percentage delegation. * Does not reset delegation mode back to NOTSET. **/ function undelegateAll() external; /** * @notice Undelegate all explicit vote power by amount delegates for `msg.sender`. * Can only be used with explicit delegation. * Does not reset delegation mode back to NOTSET. * @param _delegateAddresses Explicit delegation does not store delegatees' addresses, * so the caller must supply them. * @return The amount still delegated (in case the list of delegates was incomplete). */ function undelegateAllExplicit(address[] memory _delegateAddresses) external returns (uint256); /** * @dev Should be compatible with ERC20 method */ function name() external view returns (string memory); /** * @dev Should be compatible with ERC20 method */ function symbol() external view returns (string memory); /** * @dev Should be compatible with ERC20 method */ function decimals() external view returns (uint8); /** * @notice Total amount of tokens at a specific `_blockNumber`. * @param _blockNumber The block number when the totalSupply is queried * @return The total amount of tokens at `_blockNumber` **/ function totalSupplyAt(uint _blockNumber) external view returns(uint256); /** * @dev Queries the token balance of `_owner` at a specific `_blockNumber`. * @param _owner The address from which the balance will be retrieved. * @param _blockNumber The block number when the balance is queried. * @return The balance at `_blockNumber`. **/ function balanceOfAt(address _owner, uint _blockNumber) external view returns (uint256); /** * @notice Get the current total vote power. * @return The current total vote power (sum of all accounts' vote powers). */ function totalVotePower() external view returns(uint256); /** * @notice Get the total vote power at block `_blockNumber` * @param _blockNumber The block number at which to fetch. * @return The total vote power at the block (sum of all accounts' vote powers). */ function totalVotePowerAt(uint _blockNumber) external view returns(uint256); /** * @notice Get the current vote power of `_owner`. * @param _owner The address to get voting power. * @return Current vote power of `_owner`. */ function votePowerOf(address _owner) external view returns(uint256); /** * @notice Get the vote power of `_owner` at block `_blockNumber` * @param _owner The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_owner` at `_blockNumber`. */ function votePowerOfAt(address _owner, uint256 _blockNumber) external view returns(uint256); /** * @notice Get the vote power of `_owner` at block `_blockNumber`, ignoring revocation information (and cache). * @param _owner The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_owner` at `_blockNumber`. Result doesn't change if vote power is revoked. */ function votePowerOfAtIgnoringRevocation(address _owner, uint256 _blockNumber) external view returns(uint256); /** * @notice Get the delegation mode for '_who'. This mode determines whether vote power is * allocated by percentage or by explicit value. Once the delegation mode is set, * it never changes, even if all delegations are removed. * @param _who The address to get delegation mode. * @return delegation mode: 0 = NOTSET, 1 = PERCENTAGE, 2 = AMOUNT (i.e. explicit) */ function delegationModeOf(address _who) external view returns(uint256); /** * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee. * @param _from Address of delegator * @param _to Address of delegatee * @return The delegated vote power. */ function votePowerFromTo(address _from, address _to) external view returns(uint256); /** * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`. * @param _from Address of delegator * @param _to Address of delegatee * @param _blockNumber The block number at which to fetch. * @return The delegated vote power. */ function votePowerFromToAt(address _from, address _to, uint _blockNumber) external view returns(uint256); /** * @notice Compute the current undelegated vote power of `_owner` * @param _owner The address to get undelegated voting power. * @return The unallocated vote power of `_owner` */ function undelegatedVotePowerOf(address _owner) external view returns(uint256); /** * @notice Get the undelegated vote power of `_owner` at given block. * @param _owner The address to get undelegated voting power. * @param _blockNumber The block number at which to fetch. * @return The undelegated vote power of `_owner` (= owner's own balance minus all delegations from owner) */ function undelegatedVotePowerOfAt(address _owner, uint256 _blockNumber) external view returns(uint256); /** * @notice Get the vote power delegation `delegationAddresses` * and `_bips` of `_who`. Returned in two separate positional arrays. * @param _who The address to get delegations. * @return _delegateAddresses Positional array of delegation addresses. * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent) * @return _count The number of delegates. * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2). */ function delegatesOf(address _who) external view returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ); /** * @notice Get the vote power delegation `delegationAddresses` * and `pcts` of `_who`. Returned in two separate positional arrays. * @param _who The address to get delegations. * @param _blockNumber The block for which we want to know the delegations. * @return _delegateAddresses Positional array of delegation addresses. * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent) * @return _count The number of delegates. * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2). */ function delegatesOfAt(address _who, uint256 _blockNumber) external view returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ); /** * Returns VPContract used for readonly operations (view methods). * The only non-view method that might be called on it is `revokeDelegationAt`. * * @notice `readVotePowerContract` is almost always equal to `writeVotePowerContract` * except during upgrade from one VPContract to a new version (which should happen * rarely or never and will be anounced before). * * @notice You shouldn't call any methods on VPContract directly, all are exposed * via VPToken (and state changing methods are forbidden from direct calls). * This is the reason why this method returns `IVPContractEvents` - it should only be used * for listening to events (`Revoke` only). */ function readVotePowerContract() external view returns (IVPContractEvents); /** * Returns VPContract used for state changing operations (non-view methods). * The only non-view method that might be called on it is `revokeDelegationAt`. * * @notice `writeVotePowerContract` is almost always equal to `readVotePowerContract` * except during upgrade from one VPContract to a new version (which should happen * rarely or never and will be anounced before). In the case of upgrade, * `writeVotePowerContract` will be replaced first to establish delegations, and * after some perio (e.g. after a reward epoch ends) `readVotePowerContract` will be set equal to it. * * @notice You shouldn't call any methods on VPContract directly, all are exposed * via VPToken (and state changing methods are forbidden from direct calls). * This is the reason why this method returns `IVPContractEvents` - it should only be used * for listening to events (`Delegate` and `Revoke` only). */ function writeVotePowerContract() external view returns (IVPContractEvents); /** * When set, allows token owners to participate in governance voting * and delegate governance vote power. */ function governanceVotePower() external view returns (IGovernanceVotePower); }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_flareDaemon","internalType":"contract FlareDaemon"},{"type":"address","name":"_addressUpdater","internalType":"address"},{"type":"address","name":"_priceSubmitter","internalType":"contract IIPriceSubmitter"},{"type":"address","name":"_oldFtsoManager","internalType":"contract IIFtsoManagerV1"},{"type":"uint256","name":"_firstPriceEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_priceEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_revealEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_firstRewardEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_rewardEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_votePowerIntervalFraction","internalType":"uint256"}]},{"type":"event","name":"AccruingUnearnedRewardsFailed","inputs":[{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CleanupBlockNumberManagerFailedForBlock","inputs":[{"type":"uint256","name":"blockNumber","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ClosingExpiredRewardEpochFailed","inputs":[{"type":"uint256","name":"rewardEpoch","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContractRevertError","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}],"anonymous":false},{"type":"event","name":"DistributingRewardsFailed","inputs":[{"type":"address","name":"ftso","internalType":"address","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FallbackMode","inputs":[{"type":"bool","name":"fallbackMode","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FinalizingPriceEpochFailed","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false},{"type":"uint8","name":"failingType","internalType":"enum IFtso.PriceFinalizationType","indexed":false}],"anonymous":false},{"type":"event","name":"FtsoAdded","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"bool","name":"add","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FtsoDeactivationFailed","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false}],"anonymous":false},{"type":"event","name":"FtsoFallbackMode","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"bool","name":"fallbackMode","internalType":"bool","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":"InitializingCurrentEpochStateForRevealFailed","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PriceEpochFinalized","inputs":[{"type":"address","name":"chosenFtso","internalType":"address","indexed":false},{"type":"uint256","name":"rewardEpochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardEpochFinalized","inputs":[{"type":"uint256","name":"votepowerBlock","internalType":"uint256","indexed":false},{"type":"uint256","name":"startBlock","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":"event","name":"UpdatingActiveValidatorsTriggerFailed","inputs":[{"type":"uint256","name":"rewardEpoch","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_TRUSTED_ADDRESSES_LENGTH","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"active","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addFtso","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addFtsosBulk","inputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract CleanupBlockNumberManager"}],"name":"cleanupBlockNumberManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentRewardEpochEnds","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"daemonize","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deactivateFtsos","inputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint192","name":"totalRevertedErrors","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":"","internalType":"contract FlareDaemon"}],"name":"flareDaemon","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"ftsoRegistry","internalType":"contract IIFtsoRegistry"},{"type":"address","name":"voterWhitelister","internalType":"contract IIVoterWhitelister"}],"name":"ftsoManagement","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoRegistry"}],"name":"ftsoRegistry","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_addressUpdater","internalType":"address"}],"name":"getAddressUpdater","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"getContractName","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_priceEpochId","internalType":"uint256"},{"type":"uint256","name":"_priceEpochStartTimestamp","internalType":"uint256"},{"type":"uint256","name":"_priceEpochEndTimestamp","internalType":"uint256"},{"type":"uint256","name":"_priceEpochRevealEndTimestamp","internalType":"uint256"},{"type":"uint256","name":"_currentTimestamp","internalType":"uint256"}],"name":"getCurrentPriceEpochData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_priceEpochId","internalType":"uint256"}],"name":"getCurrentPriceEpochId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentRewardEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"_fallbackMode","internalType":"bool"},{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"},{"type":"bool[]","name":"_ftsoInFallbackMode","internalType":"bool[]"}],"name":"getFallbackMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getFtsos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_maxVotePowerNatThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_maxVotePowerAssetThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_lowAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_lowNatTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_rewardExpiryOffsetSeconds","internalType":"uint256"},{"type":"address[]","name":"_trustedAddresses","internalType":"address[]"},{"type":"bool","name":"_initialized","internalType":"bool"},{"type":"bool","name":"_changed","internalType":"bool"}],"name":"getGovernanceParameters","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_lastUnprocessedPriceEpoch","internalType":"uint256"},{"type":"uint256","name":"_lastUnprocessedPriceEpochRevealEnds","internalType":"uint256"},{"type":"bool","name":"_lastUnprocessedPriceEpochInitialized","internalType":"bool"}],"name":"getLastUnprocessedPriceEpochData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_firstPriceEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_priceEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_revealEpochDurationSeconds","internalType":"uint256"}],"name":"getPriceEpochConfiguration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIPriceSubmitter"}],"name":"getPriceSubmitter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_firstRewardEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_rewardEpochDurationSeconds","internalType":"uint256"}],"name":"getRewardEpochConfiguration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IIFtsoManager.RewardEpochData","components":[{"type":"uint256","name":"votepowerBlock","internalType":"uint256"},{"type":"uint256","name":"startBlock","internalType":"uint256"},{"type":"uint256","name":"startTimestamp","internalType":"uint256"}]}],"name":"getRewardEpochData","inputs":[{"type":"uint256","name":"_rewardEpochId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRewardEpochToExpireNext","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_votepowerBlock","internalType":"uint256"}],"name":"getRewardEpochVotePowerBlock","inputs":[{"type":"uint256","name":"_rewardEpoch","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getVotePowerIntervalFraction","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":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_initialGovernance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"lastRewardedFtsoAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"notInitializedFtsos","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoManagerV1"}],"name":"oldFtsoManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIPriceSubmitter"}],"name":"priceSubmitter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"productionMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeFtso","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"replaceFtso","inputs":[{"type":"address","name":"_ftsoToAdd","internalType":"contract IIFtso"},{"type":"bool","name":"_copyCurrentPrice","internalType":"bool"},{"type":"bool","name":"_copyAssetOrAssetFtsos","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"replaceFtsosBulk","inputs":[{"type":"address[]","name":"_ftsosToAdd","internalType":"contract IIFtso[]"},{"type":"bool","name":"_copyCurrentPrice","internalType":"bool"},{"type":"bool","name":"_copyAssetOrAssetFtsos","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochDurationSeconds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_votepowerBlock","internalType":"uint256"},{"type":"uint256","name":"_startBlock","internalType":"uint256"},{"type":"uint256","name":"_startTimestamp","internalType":"uint256"}],"name":"rewardEpochs","inputs":[{"type":"uint256","name":"_rewardEpochId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochsStartTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoRewardManager"}],"name":"rewardManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFallbackMode","inputs":[{"type":"bool","name":"_fallbackMode","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoAsset","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"address","name":"_asset","internalType":"contract IIVPToken"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoAssetFtsos","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"address[]","name":"_assetFtsos","internalType":"contract IIFtso[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoFallbackMode","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"bool","name":"_fallbackMode","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setGovernanceParameters","inputs":[{"type":"uint256","name":"_maxVotePowerNatThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_maxVotePowerAssetThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_lowAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_lowNatTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_rewardExpiryOffsetSeconds","internalType":"uint256"},{"type":"address[]","name":"_trustedAddresses","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setInitialRewardData","inputs":[{"type":"uint256","name":"_nextRewardEpochToExpire","internalType":"uint256"},{"type":"uint256","name":"_rewardEpochsLength","internalType":"uint256"},{"type":"uint256","name":"_currentRewardEpochEnds","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardEpochDurationSeconds","inputs":[{"type":"uint256","name":"_rewardEpochDurationSeconds","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setUpdateOnRewardEpochSwitchover","inputs":[{"type":"address","name":"_updateValidators","internalType":"contract IUpdateValidators"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setVotePowerIntervalFraction","inputs":[{"type":"uint256","name":"_votePowerIntervalFraction","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"maxVotePowerNatThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"maxVotePowerAssetThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"lowAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"highAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"highAssetTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"lowNatTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"rewardExpiryOffsetSeconds","internalType":"uint256"},{"type":"bool","name":"changed","internalType":"bool"},{"type":"bool","name":"initialized","internalType":"bool"}],"name":"settings","inputs":[]},{"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":"_totalRevertedErrors","internalType":"uint256"}],"name":"showLastRevertedError","inputs":[]},{"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":"_totalRevertedErrors","internalType":"uint256"}],"name":"showRevertedErrors","inputs":[{"type":"uint256","name":"startIndex","internalType":"uint256"},{"type":"uint256","name":"numErrorTypesToShow","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IISupply"}],"name":"supply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"switchToFallbackMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"switchToProductionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256"},{"type":"bytes","name":"encodedCall","internalType":"bytes"}],"name":"timelockedCalls","inputs":[{"type":"bytes4","name":"","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateContractAddresses","inputs":[{"type":"bytes32[]","name":"_contractNameHashes","internalType":"bytes32[]"},{"type":"address[]","name":"_contractAddresses","internalType":"address[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IUpdateValidators"}],"name":"updateOnRewardEpochSwitchover","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIVoterWhitelister"}],"name":"voterWhitelister","inputs":[]}]
Contract Creation Code
0x6101606040523480156200001257600080fd5b5060405162005e4138038062005e41833981016040819052620000359162000548565b888b8b81806001600160a01b038116156200005557620000558162000461565b506001600160a01b038116620000a5576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b506001600160a01b038116620000f6576040805162461bcd60e51b8152602060048201526011602482015270666c617265206461656d6f6e207a65726f60781b604482015290519081900360640190fd5b60601b6001600160601b03191660805250620001128162000524565b50854210156040518060400160405280601e81526020017f46697273742065706f636820737461727420747320696e20667574757265000081525090620001775760405162461bcd60e51b81526004016200016e919062000604565b60405180910390fd5b5060408051808201909152600e81526d05265776172642065706f636820360941b602082015282620001be5760405162461bcd60e51b81526004016200016e919062000604565b5060408051808201909152600d81526c050726963652065706f6368203609c1b602082015285620002045760405162461bcd60e51b81526004016200016e919062000604565b5060408051808201909152601481527f52657665616c2070726963652065706f636820300000000000000000000000006020820152846200025a5760405162461bcd60e51b81526004016200016e919062000604565b5060408051808201909152601e81527f566f746520706f77657220696e74657276616c206672616374696f6e20300000602082015281620002b05760405162461bcd60e51b81526004016200016e919062000604565b5060408051808201909152601b81527f52657665616c2070726963652065706f636820746f6f206c6f6e6700000000006020820152858510620003085760405162461bcd60e51b81526004016200016e919062000604565b508284870111156040518060400160405280601b81526020017f5265776172642065706f636820737461727420746f6f20736f6f6e000000000081525090620003665760405162461bcd60e51b81526004016200016e919062000604565b50848685850303816200037557fe5b0660001460405180606001604052806024815260200162005e1d6024913990620003b45760405162461bcd60e51b81526004016200016e919062000604565b50848281620003bf57fe5b0660001460405180606001604052806027815260200162005df66027913990620003fe5760405162461bcd60e51b81526004016200016e919062000604565b50610100839052601b829055601c81905560a086905260c085905260e0849052601983905584868403816200042f57fe5b046018555050505050606092831b6001600160601b0319908116610120529190921b1661014052506200067392505050565b600054600160a01b900460ff1615620004c1576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b60008060008060008060008060008060006101608c8e0312156200056a578687fd5b8b5162000577816200065a565b60208d0151909b506200058a816200065a565b60408d0151909a506200059d816200065a565b60608d0151909950620005b0816200065a565b60808d0151909850620005c3816200065a565b8097505060a08c0151955060c08c0151945060e08c015193506101008c015192506101208c015191506101408c015190509295989b509295989b9093969950565b6000602080835283518082850152825b81811015620006325785810183015185820160400152820162000614565b81811115620006445783604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146200067057600080fd5b50565b60805160601c60a05160c05160e051610100516101205160601c6101405160601c6156a46200075260003980611ef15280613dd5525080610830528061232a52806129745280612efe528061357f525080610a155280611c1f52806127b252806128cd5250806109ec5280611b155280613f0352806146c852508061092d52806109cb5280611ae452806123aa5280612c175280613ee15280614050528061426952806146a55250806109aa5280611ac352806123cb5280613ebf528061402b52806146805250806113895280611bfb528061206e52506156a46000f3fe608060405234801561001057600080fd5b50600436106103db5760003560e01c806374e6310e1161020a578063b4dba0f311610125578063e22fdece116100b8578063f2edab5a11610087578063f2edab5a146107bb578063f5a98383146107ce578063f5f5ba72146107d6578063f937d6ad146107eb578063ff882fbb146107f3576103db565b8063e22fdece14610775578063e371aef01461077d578063e5399da314610793578063e7c830d4146107b3576103db565b8063d89c39e6116100f4578063d89c39e614610735578063e06174e41461073d578063e080a9701461075a578063e17f212e1461076d576103db565b8063b4dba0f3146106fd578063c2b0d47b14610705578063ce69f8331461070d578063d429cfe514610722576103db565b8063a10775321161019d578063a7d2acfa1161016c578063a7d2acfa146106ae578063a93a6f42146106c4578063af946af7146106d7578063b00c0b76146106ea576103db565b8063a107753214610678578063a578f55b14610680578063a670ff8714610688578063a795f4091461069b576103db565b80638de306b1116101d95780638de306b1146106265780639131205b1461063957806393a790251461064c5780639d6a890f14610665576103db565b806374e6310e146105d7578063758ff1da146105f8578063823033a91461060b57806385f3c9c91461061e576103db565b80633fdeb7e1116102fa57806360f2c5b21161028d5780636b65cc341161025c5780636b65cc34146105925780636ca051e6146105a55780636d0e8c34146105bc5780636ea0aa31146105c4576103db565b806360f2c5b21461056757806362354e031461056f57806367fc40291461057757806369b11ac61461058a576103db565b80635835cf30116102c95780635835cf30146105265780635904089a146105445780635aa6e6751461054c5780635ff2707914610554576103db565b80633fdeb7e1146104ec5780634b48dd5e146104ff5780634eac870f146105165780635267a15d1461051e576103db565b80631cb513f711610372578063361b545911610341578063361b5459146104b65780633758e679146104c957806338b5f869146104dc5780633e7ff857146104e4576103db565b80631cb513f71461046c5780632663f1b4146104825780632b3c41a4146104955780632fd8eb7d146104ae576103db565b80630f15f4c0116103ae5780630f15f4c0146104305780630f4ef8a61461043a578063132c7e1f14610442578063144e159114610455576103db565b806302fb0c5e146103e0578063047fc9aa146103fe57806308a7f402146104135780630e063d7d14610428575b600080fd5b6103e8610806565b6040516103f59190615188565b60405180910390f35b61040661080f565b6040516103f59190614fe1565b61041b61081e565b6040516103f5919061537c565b61040661082e565b610438610852565b005b6104066108a0565b610438610450366004614dc2565b6108af565b61045d6109a8565b6040516103f5939291906153c4565b610474610a10565b6040516103f592919061539e565b6104386104903660046149d3565b610a37565b61049d610a76565b6040516103f59594939291906150e9565b610406610ab1565b6104386104c4366004614dc2565b610ac0565b6104386104d7366004614d5d565b610b4c565b610406610b9b565b61041b610baa565b6104386104fa3660046149d3565b610bb0565b610507610bff565b6040516103f593929190615193565b610406610cde565b610406610ced565b61052e610d12565b6040516103f59a99989796959493929190615441565b610406610dd9565b610406610de8565b610438610562366004614cbe565b610e7c565b61041b6111d1565b6104066111d7565b610438610585366004614cbe565b6111e2565b61041b6112c5565b6104386105a0366004614d8a565b6112ca565b6105ad61136b565b6040516103f5939291906153ac565b6103e861137c565b61049d6105d2366004614df2565b611487565b6105ea6105e5366004614cbe565b6117e2565b6040516103f5929190615385565b610438610606366004614c49565b611888565b6103e86106193660046149d3565b6118ef565b61041b611911565b610438610634366004614b77565b611917565b610438610647366004614e6b565b6119b5565b610654611aad565b6040516103f59594939291906153da565b6104386106733660046149d3565b611b40565b610406611bf9565b61041b611c1d565b6104386106963660046149d3565b611c41565b61045d6106a9366004614dc2565b611caa565b6106b6611cd3565b6040516103f59291906151f1565b6104386106d2366004614ce6565b611ce9565b6104386106e5366004614d29565b611d80565b6104386106f8366004614ac1565b611e48565b610406611eef565b610406611f13565b610715611f22565b6040516103f591906150d6565b610438610730366004614b77565b611f2c565b61041b611f93565b610745611f99565b6040516103f5999897969594939291906154a0565b610438610768366004614e13565b611fc0565b6103e8612051565b6103e8612061565b61078561213f565b6040516103f592919061535a565b6107a66107a1366004614dc2565b612160565b6040516103f59190615278565b61041b6121d1565b61041b6107c9366004614dc2565b612237565b610438612249565b6107de612303565b6040516103f59190615265565b610406612328565b610438610801366004614ca4565b61234c565b60055460ff1681565b601f546001600160a01b031681565b60006108286123a6565b90505b90565b7f000000000000000000000000000000000000000000000000000000000000000090565b600054600160b01b900460ff16806108745750600054600160a81b900460ff16155b15610893576108816123f9565b6005805460ff1916600117905561089e565b61089e60003661242e565b565b601e546001600160a01b031681565b600054600160b01b900460ff16806108d15750600054600160a81b900460ff16155b1561099a576108de6123f9565b60408051808201909152600e81526d05265776172642065706f636820360941b60208201528161092a5760405162461bcd60e51b81526004016109219190615265565b60405180910390fd5b507f0000000000000000000000000000000000000000000000000000000000000000818161095457fe5b06600014604051806060016040528060278152602001615627602791399061098f5760405162461bcd60e51b81526004016109219190615265565b50601b8190556109a5565b6109a560003661242e565b50565b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000909192565b601b547f000000000000000000000000000000000000000000000000000000000000000091565b600054600160b01b900460ff1680610a595750600054600160a81b900460ff16155b1561099a57610a666123f9565b610a718160016125b1565b6109a5565b600454606090819081908190600090610aa090600160c01b90046001600160401b03166001611487565b945094509450945094509091929394565b6007546001600160a01b031681565b600054600160b01b900460ff1680610ae25750600054600160a81b900460ff16155b1561099a57610aef6123f9565b60408051808201909152601e81527f566f746520706f77657220696e74657276616c206672616374696f6e20300000602082015281610b415760405162461bcd60e51b81526004016109219190615265565b50601c8190556109a5565b600054600160b01b900460ff1680610b6e5750600054600160a81b900460ff16155b15610b8b57610b7b6123f9565b610b86838383612630565b610b96565b610b9660003661242e565b505050565b6016546001600160a01b031690565b601d5490565b600054600160b01b900460ff1680610bd25750600054600160a81b900460ff16155b1561099a57610bdf6123f9565b602180546001600160a01b0319166001600160a01b0383161790556109a5565b602154600160a01b900460ff16606080610c176126b3565b8051909250806001600160401b0381118015610c3257600080fd5b50604051908082528060200260200182016040528015610c5c578160200160208202803683370190505b50915060005b81811015610cd75760136002016000858381518110610c7d57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900460ff16838281518110610cbf57fe5b91151560209283029190910190910152600101610c62565b5050909192565b6020546001600160a01b031681565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b600a54600b54600c54600d54600e54600f54601054601254601180546040805160208084028201810190925282815260009b8c9b8c9b8c9b8c9b8c9b8c9b60609b8d9b8c9b989a979996989597949693959294909360ff61010084048116949316929091859190830182828015610db257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610d94575b50505050509250995099509950995099509950995099509950995090919293949596979899565b6021546001600160a01b031681565b60008054600160a81b900460ff16610e0b576000546001600160a01b0316610828565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4b57600080fd5b505afa158015610e5f573d6000803e3d6000fd5b505050506040513d6020811015610e7557600080fd5b5051905090565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b158015610ec057600080fd5b505afa158015610ed4573d6000803e3d6000fd5b505050506040513d6020811015610eea57600080fd5b5051610f2d576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610f99576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b8054421015610fef576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156110895780601f1061105e57610100808354040283529160200191611089565b820191906000526020600020905b81548152906001019060200180831161106c57829003601f168201915b5050506001600160e01b03198616600090815260016020819052604082208281559495509092506110bd9150830182614799565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106111055780518252601f1990920191602091820191016110e6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611167576040519150601f19603f3d011682016040523d82523d6000602084013e61116c565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a16111cb81612734565b50505050565b601c5490565b60076001609c1b0181565b6111ea612751565b6001600160e01b03198116600090815260016020526040902054611255576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610b9690830182614799565b600581565b600054600160b01b900460ff16806112ec5750600054600160a81b900460ff16155b1561135c576112f96123f9565b60405163d0d552dd60e01b81526001600160a01b0383169063d0d552dd90611325908490600401614fe1565b600060405180830381600087803b15801561133f57600080fd5b505af1158015611353573d6000803e3d6000fd5b50505050611367565b61136760003661242e565b5050565b601854601954601a5460ff16909192565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146113ef576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b60055460ff166114015750600061082b565b600854611415576114106127b0565b611481565b601a5460ff16801561142957504260195411155b15611436576114106128f4565b601a5460ff1615801561144b57504260095411155b1561147057611458612ee5565b611460613132565b6114686132be565b611410613415565b42601954116114815761148161355d565b50600190565b606080606080600060038054905087106040518060400160405280601081526020016f0e6e8c2e4e840d2dcc8caf040d0d2ced60831b815250906114de5760405162461bcd60e51b81526004016109219190615265565b5060035460009088880111156114f9576003548890036114fb565b865b9050806001600160401b038111801561151357600080fd5b5060405190808252806020026020018201604052801561153d578160200160208202803683370190505b509550806001600160401b038111801561155657600080fd5b50604051908082528060200260200182016040528015611580578160200160208202803683370190505b509450806001600160401b038111801561159957600080fd5b506040519080825280602002602001820160405280156115cd57816020015b60608152602001906001900390816115b85790505b509350806001600160401b03811180156115e657600080fd5b50604051908082528060200260200182016040528015611610578160200160208202803683370190505b50925060005b818110156117c65760006003828b018154811061162f57fe5b6000918252602080832090910154808352600290915260409091205489519192506001600160c01b03169089908490811061166657fe5b6020026020010181815250506002600082815260200190815260200160002060000160189054906101000a90046001600160401b03166001600160401b03168783815181106116b157fe5b602090810291909101810191909152600082815260028083526040918290208101805483516001821615610100026000190190911692909204601f810185900485028301850190935282825290929091908301828280156117535780601f1061172857610100808354040283529160200191611753565b820191906000526020600020905b81548152906001019060200180831161173657829003601f168201915b505050505086838151811061176457fe5b60200260200101819052506002600082815260200190815260200160002060010160009054906101000a90046001600160a01b03168583815181106117a557fe5b6001600160a01b039092166020928302919091019091015250600101611616565b50506004549497939650919450926001600160c01b0316919050565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f8101859004850286018501909652858552909491939290919083018282801561187e5780601f106118535761010080835404028352916020019161187e565b820191906000526020600020905b81548152906001019060200180831161186157829003601f168201915b5050505050905082565b600054600160b01b900460ff16806118aa5750600054600160a81b900460ff16155b15610b8b576118b76123f9565b60005b83518110156118e9576118e18482815181106118d257fe5b60200260200101518484612630565b6001016118ba565b50610b96565b6001600160a01b03811660009081526014602052604090205460ff165b919050565b601b5481565b600054600160b01b900460ff16806119395750600054600160a81b900460ff16155b1561099a576119466123f9565b60405163984626c360e01b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e9063984626c390611980906013908590600401615299565b60006040518083038186803b15801561199857600080fd5b505af41580156119ac573d6000803e3d6000fd5b505050506109a5565b600054600160b01b900460ff16806119d75750600054600160a81b900460ff16155b15611a98576119e46123f9565b6000881180156119f45750600087115b8015611a005750858510155b8015611a0e57506127108411155b8015611a1c57506127108311155b8015611a285750600082115b8015611a3657506005815111155b6040518060400160405280601381526020017211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b81525090611a805760405162461bcd60e51b81526004016109219190615265565b50611a93600a898989898989898961388c565b611aa3565b611aa360003661242e565b5050505050505050565b600080600080600080611abe6123a6565b9550507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000808702820195506001870102019250507f000000000000000000000000000000000000000000000000000000000000000082019050429091929394565b600054600160a01b900460ff1615611b96576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b600054600160b01b900460ff1680611c635750600054600160a81b900460ff16155b1561099a57611c706123f9565b604051635d9fe31360e01b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e90635d9fe313906119809060139085906004016152b2565b600080600080611cb985612160565b805160208201516040909201519097919650945092505050565b6016546017546001600160a01b03918216911682565b600054600160b01b900460ff1680611d0b5750600054600160a81b900460ff16155b1561135c57611d186123f9565b604051636904d3eb60e11b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e9063d209a7d690611d5490601390869086906004016152c9565b60006040518083038186803b158015611d6c57600080fd5b505af4158015611353573d6000803e3d6000fd5b611d88612751565b6001600160a01b0382166000908152601360209081526040918290205482518084019093526009835268139bdd08199bdd5b9960ba1b9183019190915260ff16611de55760405162461bcd60e51b81526004016109219190615265565b506001600160a01b03821660009081526015602052604090819020805460ff1916831515179055517f24462ede4d3e8e5a69fecec6290d42a311016ca752216d9a3d681e284791b7ac90611e3c908490849061520b565b60405180910390a15050565b611e50610ced565b6001600160a01b0316336001600160a01b031614611eac576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b611ee5611ee083836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250613a85565b613bb2565b6113678282613bd6565b7f000000000000000000000000000000000000000000000000000000000000000081565b6017546001600160a01b031690565b60606108286126b3565b600054600160b01b900460ff1680611f4e5750600054600160a81b900460ff16155b1561099a57611f5b6123f9565b60005b8151811015611f8d57611f85828281518110611f7657fe5b602002602001015160016125b1565b600101611f5e565b506109a5565b60095481565b600a54600b54600c54600d54600e54600f5460105460125460ff8082169161010090041689565b600054600160b01b900460ff1680611fe25750600054600160a81b900460ff16155b15610b8b57611fef6123f9565b600554604080518082019091526011815270105b1c9958591e481858dd1a5d985d1959607a1b60208201529060ff161561203c5760405162461bcd60e51b81526004016109219190615265565b50601d83905560088290556009819055610b96565b600054600160a81b900460ff1681565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146120d4576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b602154600160a01b900460ff16612139576021805460ff60a01b1916600160a01b1790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc9061212990600190615188565b60405180910390a150600161082b565b50600090565b6004546001600160c01b03811690600160c01b90046001600160401b031682565b6121686147dd565b60085482106040518060400160405280602081526020017f5265776172642065706f6368206e6f7420696e697469616c697a656420796574815250906121c15760405162461bcd60e51b81526004016109219190615265565b506121cb82613d8c565b92915050565b6000600854600014156040518060400160405280602081526020017f5265776172642065706f6368206e6f7420696e697469616c697a6564207965748152509061222e5760405162461bcd60e51b81526004016109219190615265565b50610828613e91565b600061224282612160565b5192915050565b612251612751565b600054600160a81b900460ff16156122b0576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600b81526a233a39b7a6b0b730b3b2b960a91b602082015290565b7f000000000000000000000000000000000000000000000000000000000000000081565b612354612751565b6021805460ff60a01b1916600160a01b831515021790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc9061239b908390615188565b60405180910390a150565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000004203816123f357fe5b04905090565b600054600160b01b900460ff16156124265733301461241457fe5b6000805460ff60b01b1916905561089e565b61089e612751565b612436612751565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561247e57600080fd5b505afa158015612492573d6000803e3d6000fd5b505050506040513d60208110156124a857600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b0319861681526001602081815260409092208451815584830151805191945061252c939285019201906147fe565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b601a546040516306b8c18560e01b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e916306b8c185916125f791601391600a918891889160ff16906004016152f3565b60006040518083038186803b15801561260f57600080fd5b505af4158015612623573d6000803e3d6000fd5b5050505061136782613e9b565b601a5460405163169ffdc760e21b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e91635a7ff71c9161267a91601391600a9189918991899160ff90911690600401615323565b60006040518083038186803b15801561269257600080fd5b505af41580156126a6573d6000803e3d6000fd5b50505050610b9683613e9b565b60165460408051635200305d60e11b815290516060926001600160a01b03169163a40060ba916004808301926000929190829003018186803b1580156126f857600080fd5b505afa15801561270c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108289190810190614bb1565b3d604051818101604052816000823e821561274d578181f35b8181fd5b612759610de8565b6001600160a01b0316336001600160a01b03161461089e576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b7f0000000000000000000000000000000000000000000000000000000000000000421061089e5760006127e16126b3565b80516040805160608101825243600019810182526020808301918252428385019081526008805460009081526006909352948220845181559251600180850191909155905160029093019290925583549091019092559293509091905b828110156128c65783818151811061285257fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b8152600401612889919061537c565b600060405180830381600087803b1580156128a357600080fd5b505af11580156128b7573d6000803e3d6000fd5b5050505080600101905061283e565b5050601b547f0000000000000000000000000000000000000000000000000000000000000000016009555050565b60006128fe6126b3565b8051909150801580159061291c5750602154600160a01b900460ff16155b15612dfb576007546000906001600160a01b03166129705781444260405160200161294892919061539e565b6040516020818303038152906040528051906020012060001c8161296857fe5b069050612a3e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156129cb57600080fd5b505afa1580156129df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a039190614dda565b9050828142604051602001612a1992919061539e565b6040516020818303038152906040528051906020012060001c81612a3957fe5b069150505b60608060008080805b87811015612be35760008882890181612a5c57fe5b06905060008a8281518110612a6d57fe5b6020908102919091018101516001600160a01b0381166000908152601490925260409091205490915060ff1615612ac3576001600160a01b03166000908152601460205260409020805460ff1916905550612bdb565b6018546040516340462a2d60e01b81526001600160a01b038316916340462a2d91612af49190891590600401615255565b600060405180830381600087803b158015612b0e57600080fd5b505af1925050508015612b4357506040513d6000823e601f3d908101601f19168201604052612b4091908101906149f6565b60015b612bae57612b4f615529565b80612b5a5750612b6a565b612b648282613fd8565b50612ba9565b612ba9816040518060400160405280601881526020017f6572722066696e616c697a652070726963652065706f63680000000000000000815250613fd8565b612bd8565b87158015612bbd575060008351115b15612bd45791995097509550600194509250828787875b5050505b50505b600101612a47565b506000612bee613e91565b90508215612d9257601e546018546001600160a01b039091169063a9b79e1790889088908890877f0000000000000000000000000000000000000000000000000000000000000000886001612c4285614029565b03612c4c8b613d8c565b516040516001600160e01b031960e08c901b168152612c7699989796959493929190600401615059565b600060405180830381600087803b158015612c9057600080fd5b505af1925050508015612ca1575060015b612d8d57612cad615529565b80612cb85750612d0f565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c83601854604051612ceb929190614ff5565b60405180910390a1601e54612d09906001600160a01b031682614076565b50612d8d565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c82601854604051612d42929190614ff5565b60405180910390a1601e546040805180820190915260168152756572722064697374726962757465207265776172647360501b6020820152612d8d916001600160a01b031690614076565b612d9a565b612d9a61424f565b600780546001600160a01b0319166001600160a01b0384161790556040517f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad90612de79084908490614ff5565b60405180910390a150505050505050612ed7565b60005b81811015612e7c576000838281518110612e1457fe5b6020908102919091018101516001600160a01b0381166000908152601490925260409091205490915060ff1615612e69576001600160a01b03166000908152601460205260409020805460ff19169055612e74565b612e72816143d1565b505b600101612dfe565b50612e8561424f565b600780546001600160a01b03191690557f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad6000612ec0613e91565b604051612ece929190614ff5565b60405180910390a15b5050601a805460ff19169055565b6000612eef6126b3565b905060008151905060004290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f5557600080fd5b505afa158015612f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8d9190614dda565b604051910190612fa190829060200161537c565b6040516020818303038152906040528051906020012060001c90506000601c54612fd1612fcc613e91565b613d8c565b60200151430381612fde57fe5b04905080612fea575060015b6000818381612ff557fe5b06905080613001575060015b60408051606081018252438381038252602080830191825242838501908152600880546000908152600690935294822084518155925160018085019190915590516002909301929092558354909101909255905b858110156130de5786818151811061306957fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b81526004016130a0919061537c565b600060405180830381600087803b1580156130ba57600080fd5b505af11580156130ce573d6000803e3d6000fd5b5050600190920191506130559050565b50805160208201516040517f1813f880dc24666c8b69c9d771a487ea620a27fde1514be3112847056c0c53229261311692909161539e565b60405180910390a15050601b5460098054909101905550505050565b600061313c613e91565b60105490915042035b81601d54108015613167575080613160601d54600101613d8c565b6040015111155b1561136757601e54601d54604051636b60edf760e11b81526001600160a01b039092169163d6c1dbee9161319d9160040161537c565b600060405180830381600087803b1580156131b757600080fd5b505af19250505080156131c8575060015b6132b0576131d4615529565b806131df5750613234565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d601d54604051613210919061537c565b60405180910390a1601e5461322e906001600160a01b031682614076565b50611367565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d601d54604051613265919061537c565b60405180910390a1601e54604080518082019091526011815270195c9c8818db1bdcd948195e1c1a5c9959607a1b60208201526132ab916001600160a01b031690614076565b611367565b601d80546001019055613145565b60006132cb601d54613d8c565b5160205460405163cbc31cf760e01b81529192506001600160a01b03169063cbc31cf7906132fd90849060040161537c565b600060405180830381600087803b15801561331757600080fd5b505af1925050508015613328575060015b6109a557613334615529565b8061333f5750613392565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d8260405161336e919061537c565b60405180910390a160205461338c906001600160a01b031682614076565b50610a71565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d816040516133c1919061537c565b60405180910390a1610a71602060009054906101000a90046001600160a01b0316604051806040016040528060158152602001746572722073657420636c65616e757020626c6f636b60581b815250614076565b6021546001600160a01b03161561089e576000613430613e91565b9050602160009054906101000a90046001600160a01b03166001600160a01b03166321eb1a956040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561348257600080fd5b505af1925050508015613493575060015b6109a55761349f615529565b806134aa57506134f7565b7ff7c7d6681321cc290eb89e8c96dba504436073b8bb277945cc32177e5181dd84826040516134d9919061537c565b60405180910390a160215461338c906001600160a01b031682614076565b7ff7c7d6681321cc290eb89e8c96dba504436073b8bb277945cc32177e5181dd8481604051613526919061537c565b60405180910390a160215460408051606081019091526022808252610a71926001600160a01b031691906156056020830139614076565b60125460ff16156135e857604051639ec2b58160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639ec2b581906135b5906011906004016150c3565b600060405180830381600087803b1580156135cf57600080fd5b505af11580156135e3573d6000803e3d6000fd5b505050505b60006135f26126b3565b8051909150600081158015906136125750602154600160a01b900460ff16155b156136ab576000613624612fcc613e91565b51601f546040516237b08960e41b81529192506001600160a01b03169063037b08909061365590849060040161537c565b602060405180830381600087803b15801561366f57600080fd5b505af1158015613683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a79190614dda565b9150505b60005b828110156138515760008482815181106136c457fe5b602090810291909101015160125490915060ff161561375757600a54600b54600c54600d54600e54600f5460405163f7dba1f560e01b81526001600160a01b0388169663f7dba1f5966137249691959094919390926011906004016153fd565b600060405180830381600087803b15801561373e57600080fd5b505af1158015613752573d6000803e3d6000fd5b505050505b806001600160a01b031663f670ebe384602160149054906101000a900460ff168061379a57506001600160a01b03841660009081526015602052604090205460ff165b6040518363ffffffff1660e01b81526004016137b7929190615255565b600060405180830381600087803b1580156137d157600080fd5b505af19250505080156137e2575060015b613848576137ee615529565b806137f95750613809565b613803828261446d565b50613848565b613848816040518060400160405280601981526020017f65727220696e69742065706f636820666f722072657665616c0000000000000081525061446d565b506001016136ae565b506012805460ff1916905560006138666123a6565b601881905590506138768161467e565b6019555050601a805460ff191660011790555050565b885488146138a75760088901805460ff191660011790558789555b868960010154146138ca5760088901805460ff1916600190811790915589018790555b858960020154146138ec5760088901805460ff19166001179055600289018690555b8489600301541461390e5760088901805460ff19166001179055600389018590555b838960040154146139305760088901805460ff19166001179055600489018490555b828960050154146139525760088901805460ff19166001179055600589018390555b818960060154146139745760088901805460ff19166001179055600689018290555b805160078a0154146139aa5780516139959060078b0190602084019061488a565b5060088901805460ff19166001179055613a69565b60005b8151811015613a67578181815181106139c257fe5b60200260200101516001600160a01b03168a60070182815481106139e257fe5b6000918252602090912001546001600160a01b031614613a5f5760088a01805460ff191660011790558151829082908110613a1957fe5b60200260200101518a6007018281548110613a3057fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6001016139ad565b505b5050506008909501805461ff0019166101001790555050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b83811015613ac9578181015183820152602001613ab1565b50505050905090810190601f168015613af65780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b8651811015613b5e57868181518110613b2c57fe5b6020026020010151831415613b5657858181518110613b4757fe5b60200260200101519150613b5e565b600101613b17565b506001600160a01b038116613ba9576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b613c0a828260405180604001604052806011815260200170233a39b7a932bbb0b93226b0b730b3b2b960791b815250613a85565b601e60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613c59828260405180604001604052806006815260200165537570706c7960d01b815250613a85565b601f60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613cbf82826040518060400160405280601981526020017f436c65616e7570426c6f636b4e756d6265724d616e6167657200000000000000815250613a85565b602060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613d1482826040518060400160405280600c81526020016b4674736f526567697374727960a01b815250613a85565b601680546001600160a01b0319166001600160a01b039290921691909117905560408051808201909152601081526f2b37ba32b92bb434ba32b634b9ba32b960811b6020820152613d689083908390613a85565b601780546001600160a01b0319166001600160a01b03929092169190911790555050565b613d946147dd565b50600081815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181018290529061190c5760008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a795f409866040518263ffffffff1660e01b8152600401613e1f919061537c565b60606040518083038186803b158015613e3757600080fd5b505afa158015613e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6f9190614e3e565b6040805160608101825293845260208401929092529082015295945050505050565b6008546000190190565b604051630bc29bcf60e21b81526001600160a01b03821690632f0a6f3c90613f2b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000906004016153c4565b600060405180830381600087803b158015613f4557600080fd5b505af1158015613f59573d6000803e3d6000fd5b505050506008546000146109a557806001600160a01b031663e536f396613f81612fcc613e91565b516040516001600160e01b031960e084901b168152613fa3919060040161537c565b600060405180830381600087803b158015613fbd57600080fd5b505af1158015613fd1573d6000803e3d6000fd5b5050505050565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b88182601854600160405161400e93929190615226565b60405180910390a16140208282614076565b611367826143d1565b7f0000000000000000000000000000000000000000000000000000000000000000600182017f00000000000000000000000000000000000000000000000000000000000000000201919050565b6000828260405160200161408b92919061500e565b60408051601f198184030181528282528051602091820120600081815260029092529190208054436001600160c01b038181166001600160401b03600160c01b80860482166001019091160291909316176001600160c01b031916919091179091559092507f1a601cf5e0efbd558b2778b7389af04741d1c49bcab104c40daa2da1945936179161411f9186918690615032565b60405180910390a1600480546001600160c01b0319811660016001600160c01b03928316810190921617909155600082815260026020526040902054600160c01b90046001600160401b031611156141775750611367565b6003805460018082019092557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01829055600082815260026020818152604090922092830180546001600160a01b0319166001600160a01b03881617905584516141e793909101918501906147fe565b50600354600091825260026020526040909120600101805467ffffffffffffffff60a01b1916600160a01b6000199093016001600160401b0390811684029190911791829055600480546001600160c01b03169390920416600160c01b029190911790555050565b601e546018546001600160a01b03909116906367dcac53907f0000000000000000000000000000000000000000000000000000000000000000600161429383614029565b036040518463ffffffff1660e01b81526004016142b2939291906153c4565b600060405180830381600087803b1580156142cc57600080fd5b505af19250505080156142dd575060015b61089e576142e9615529565b806142f45750614349565b7f8eb60f903ef61e0e490d7d7ba6e5b85cd949ebece7a5e5b3346eb046c041413f601854604051614325919061537c565b60405180910390a1601e54614343906001600160a01b031682614076565b506143cc565b7f8eb60f903ef61e0e490d7d7ba6e5b85cd949ebece7a5e5b3346eb046c041413f60185460405161437a919061537c565b60405180910390a1601e5460408051808201909152601b81527f6572722061636372756520756e6561726e65642072657761726473000000000060208201526143cc916001600160a01b031690614076565b61089e565b60185460405163257ea88160e11b81526001600160a01b03831691634afd5102916143ff919060040161537c565b600060405180830381600087803b15801561441957600080fd5b505af192505050801561442a575060015b6109a557614436615529565b80614441575061444b565b61338c82826146ed565b610a718160405180606001604052806021815260200161564e602191396146ed565b7f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462826144976123a6565b6040516144a5929190614ff5565b60405180910390a16144b78282614076565b602154600160a01b900460ff16806144e757506001600160a01b03821660009081526015602052604090205460ff165b15614514576001600160a01b0382166000908152601460205260409020805460ff19166001179055611367565b60405163f670ebe360e01b81526001600160a01b0383169063f670ebe39061454490600090600190600401615255565b600060405180830381600087803b15801561455e57600080fd5b505af192505050801561456f575060015b6113675761457b615529565b8061458657506145f9565b6001600160a01b0383166000908152601460205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462836145d36123a6565b6040516145e1929190614ff5565b60405180910390a16145f38382614076565b506132ab565b6001600160a01b0382166000908152601460205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462826146466123a6565b604051614654929190614ff5565b60405180910390a16132ab826040518060600160405280602281526020016155e360229139614076565b7f0000000000000000000000000000000000000000000000000000000000000000600182017f000000000000000000000000000000000000000000000000000000000000000002017f000000000000000000000000000000000000000000000000000000000000000001919050565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b88182601854600260405161472393929190615226565b60405180910390a16147358282614076565b60185460405163974d7a6b60e01b81526001600160a01b0384169163974d7a6b91614763919060040161537c565b600060405180830381600087803b15801561477d57600080fd5b505af1158015614791573d6000803e3d6000fd5b505050505050565b50805460018160011615610100020316600290046000825580601f106147bf57506109a5565b601f0160209004906000526020600020908101906109a591906148df565b60405180606001604052806000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282614834576000855561487a565b82601f1061484d57805160ff191683800117855561487a565b8280016001018555821561487a579182015b8281111561487a57825182559160200191906001019061485f565b506148869291506148df565b5090565b82805482825590600052602060002090810192821561487a579160200282015b8281111561487a57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906148aa565b5b8082111561488657600081556001016148e0565b600082601f830112614904578081fd5b8135602061491961491483615506565b6154e3565b8281528181019085830183850287018401881015614935578586fd5b855b8581101561495c57813561494a816155cd565b84529284019290840190600101614937565b5090979650505050505050565b600082601f830112614979578081fd5b8151602061498961491483615506565b82815281810190858301838502870184018810156149a5578586fd5b855b8581101561495c578151845292840192908401906001016149a7565b8035801515811461190c57600080fd5b6000602082840312156149e4578081fd5b81356149ef816155cd565b9392505050565b600080600060608486031215614a0a578182fd5b83516001600160401b0380821115614a20578384fd5b818601915086601f830112614a33578384fd5b81516020614a4361491483615506565b82815281810190858301838502870184018c1015614a5f578889fd5b8896505b84871015614a8a578051614a76816155cd565b835260019690960195918301918301614a63565b5091890151919750909350505080821115614aa3578384fd5b50614ab086828701614969565b925050604084015190509250925092565b60008060408385031215614ad3578182fd5b82356001600160401b0380821115614ae9578384fd5b818501915085601f830112614afc578384fd5b81356020614b0c61491483615506565b82815281810190858301838502870184018b1015614b28578889fd5b8896505b84871015614b4a578035835260019690960195918301918301614b2c565b5096505086013592505080821115614b60578283fd5b50614b6d858286016148f4565b9150509250929050565b600060208284031215614b88578081fd5b81356001600160401b03811115614b9d578182fd5b614ba9848285016148f4565b949350505050565b60006020808385031215614bc3578182fd5b82516001600160401b03811115614bd8578283fd5b8301601f81018513614be8578283fd5b8051614bf661491482615506565b8181528381019083850185840285018601891015614c12578687fd5b8694505b83851015614c3d578051614c29816155cd565b835260019490940193918501918501614c16565b50979650505050505050565b600080600060608486031215614c5d578081fd5b83356001600160401b03811115614c72578182fd5b614c7e868287016148f4565b935050614c8d602085016149c3565b9150614c9b604085016149c3565b90509250925092565b600060208284031215614cb5578081fd5b6149ef826149c3565b600060208284031215614ccf578081fd5b81356001600160e01b0319811681146149ef578182fd5b60008060408385031215614cf8578182fd5b8235614d03816155cd565b915060208301356001600160401b03811115614d1d578182fd5b614b6d858286016148f4565b60008060408385031215614d3b578182fd5b8235614d46816155cd565b9150614d54602084016149c3565b90509250929050565b600080600060608486031215614d71578081fd5b8335614d7c816155cd565b9250614c8d602085016149c3565b60008060408385031215614d9c578182fd5b8235614da7816155cd565b91506020830135614db7816155cd565b809150509250929050565b600060208284031215614dd3578081fd5b5035919050565b600060208284031215614deb578081fd5b5051919050565b60008060408385031215614e04578182fd5b50508035926020909101359150565b600080600060608486031215614e27578081fd5b505081359360208301359350604090920135919050565b600080600060608486031215614e52578081fd5b8351925060208401519150604084015190509250925092565b600080600080600080600080610100898b031215614e87578586fd5b883597506020890135965060408901359550606089013594506080890135935060a0890135925060c0890135915060e08901356001600160401b03811115614ecd578182fd5b614ed98b828c016148f4565b9150509295985092959890939650565b6000815180845260208085019450808401835b83811015614f215781516001600160a01b031687529582019590820190600101614efc565b509495945050505050565b6000815480845260208085019450838352808320835b83811015614f215781546001600160a01b031687529582019560019182019101614f42565b6000815180845260208085019450808401835b83811015614f2157815187529582019590820190600101614f7a565b60008151808452815b81811015614fbb57602081850181015186830182015201614f9f565b81811115614fcc5782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0383168152604060208201819052600090614ba990830184614f96565b600060018060a01b038516825283602083015260606040830152613ba96060830184614f96565b600061012080835261506d8184018d614ee9565b90508281036020840152615081818c614f67565b604084019a909a52505060608101969096526001600160a01b0394909416608086015260a085019290925260c084015260e08301526101009091015292915050565b6000602082526149ef6020830184614f2c565b6000602082526149ef6020830184614ee9565b600060a082526150fc60a0830188614f67565b60208382038185015261510f8289614f67565b848103604086015287518082529092508183019082810284018301838a01865b8381101561515d57601f1987840301855261514b838351614f96565b9486019492509085019060010161512f565b50508681036060880152615171818a614ee9565b955050505050508260808301529695505050505050565b901515815260200190565b6000841515825260206060818401526151af6060840186614ee9565b8381036040850152845180825282860191830190845b818110156151e35783511515835292840192918401916001016151c5565b509098975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b038416815260208101839052606081016006831061524757fe5b826040830152949350505050565b9182521515602082015260400190565b6000602082526149ef6020830184614f96565b81518152602080830151908201526040918201519181019190915260600190565b600083825260406020830152614ba96040830184614ee9565b9182526001600160a01b0316602082015260400190565b8381526001600160a01b0383166020820152606060408201819052600090613ba990830184614ee9565b94855260208501939093526001600160a01b03919091166040840152151560608301521515608082015260a00190565b95865260208601949094526001600160a01b039290921660408501521515606084015215156080830152151560a082015260c00190565b6001600160c01b039290921682526001600160401b0316602082015260400190565b90815260200190565b600083825260406020830152614ba96040830184614f96565b918252602082015260400190565b92835260208301919091521515604082015260600190565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b60008882528760208301528660408301528560608301528460808301528360a083015260e060c083015261543460e0830184614f2c565b9998505050505050505050565b60006101408c83528b60208401528a60408401528960608401528860808401528760a08401528660c08401528060e084015261547f81840187614ee9565b94151561010084015250509015156101209091015298975050505050505050565b988952602089019790975260408801959095526060870193909352608086019190915260a085015260c0840152151560e083015215156101008201526101200190565b6040518181016001600160401b03811182821017156154fe57fe5b604052919050565b60006001600160401b0382111561551957fe5b5060209081020190565b60e01c90565b600060443d10156155395761082b565b600481823e6308c379a061554d8251615523565b146155575761082b565b6040513d600319016004823e80513d6001600160401b038160248401118184111715615586575050505061082b565b828401925082519150808211156155a0575050505061082b565b503d830160208284010111156155b85750505061082b565b601f01601f1916810160200160405291505090565b6001600160a01b03811681146109a557600080fdfe6572722066616c6c6261636b20696e69742065706f636820666f722072657665616c6572722063616c6c696e672075706461746541637469766556616c696461746f72735265776172642065706f6368206475726174696f6e20636f6e646974696f6e20696e76616c69646572722066616c6c6261636b2066696e616c697a652070726963652065706f6368a2646970667358221220ecf6e57ae61845a2bd7a19441a33f0535c5296d449ac52253f962fd65261ce0a64736f6c634300070600335265776172642065706f6368206475726174696f6e20636f6e646974696f6e20696e76616c69645265776172642065706f636820737461727420636f6e646974696f6e20696e76616c69640000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b000000000000000000000000100000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000062cf1e4600000000000000000000000000000000000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000062d9a2300000000000000000000000000000000000000000000000000000000000049d400000000000000000000000000000000000000000000000000000000000000002
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106103db5760003560e01c806374e6310e1161020a578063b4dba0f311610125578063e22fdece116100b8578063f2edab5a11610087578063f2edab5a146107bb578063f5a98383146107ce578063f5f5ba72146107d6578063f937d6ad146107eb578063ff882fbb146107f3576103db565b8063e22fdece14610775578063e371aef01461077d578063e5399da314610793578063e7c830d4146107b3576103db565b8063d89c39e6116100f4578063d89c39e614610735578063e06174e41461073d578063e080a9701461075a578063e17f212e1461076d576103db565b8063b4dba0f3146106fd578063c2b0d47b14610705578063ce69f8331461070d578063d429cfe514610722576103db565b8063a10775321161019d578063a7d2acfa1161016c578063a7d2acfa146106ae578063a93a6f42146106c4578063af946af7146106d7578063b00c0b76146106ea576103db565b8063a107753214610678578063a578f55b14610680578063a670ff8714610688578063a795f4091461069b576103db565b80638de306b1116101d95780638de306b1146106265780639131205b1461063957806393a790251461064c5780639d6a890f14610665576103db565b806374e6310e146105d7578063758ff1da146105f8578063823033a91461060b57806385f3c9c91461061e576103db565b80633fdeb7e1116102fa57806360f2c5b21161028d5780636b65cc341161025c5780636b65cc34146105925780636ca051e6146105a55780636d0e8c34146105bc5780636ea0aa31146105c4576103db565b806360f2c5b21461056757806362354e031461056f57806367fc40291461057757806369b11ac61461058a576103db565b80635835cf30116102c95780635835cf30146105265780635904089a146105445780635aa6e6751461054c5780635ff2707914610554576103db565b80633fdeb7e1146104ec5780634b48dd5e146104ff5780634eac870f146105165780635267a15d1461051e576103db565b80631cb513f711610372578063361b545911610341578063361b5459146104b65780633758e679146104c957806338b5f869146104dc5780633e7ff857146104e4576103db565b80631cb513f71461046c5780632663f1b4146104825780632b3c41a4146104955780632fd8eb7d146104ae576103db565b80630f15f4c0116103ae5780630f15f4c0146104305780630f4ef8a61461043a578063132c7e1f14610442578063144e159114610455576103db565b806302fb0c5e146103e0578063047fc9aa146103fe57806308a7f402146104135780630e063d7d14610428575b600080fd5b6103e8610806565b6040516103f59190615188565b60405180910390f35b61040661080f565b6040516103f59190614fe1565b61041b61081e565b6040516103f5919061537c565b61040661082e565b610438610852565b005b6104066108a0565b610438610450366004614dc2565b6108af565b61045d6109a8565b6040516103f5939291906153c4565b610474610a10565b6040516103f592919061539e565b6104386104903660046149d3565b610a37565b61049d610a76565b6040516103f59594939291906150e9565b610406610ab1565b6104386104c4366004614dc2565b610ac0565b6104386104d7366004614d5d565b610b4c565b610406610b9b565b61041b610baa565b6104386104fa3660046149d3565b610bb0565b610507610bff565b6040516103f593929190615193565b610406610cde565b610406610ced565b61052e610d12565b6040516103f59a99989796959493929190615441565b610406610dd9565b610406610de8565b610438610562366004614cbe565b610e7c565b61041b6111d1565b6104066111d7565b610438610585366004614cbe565b6111e2565b61041b6112c5565b6104386105a0366004614d8a565b6112ca565b6105ad61136b565b6040516103f5939291906153ac565b6103e861137c565b61049d6105d2366004614df2565b611487565b6105ea6105e5366004614cbe565b6117e2565b6040516103f5929190615385565b610438610606366004614c49565b611888565b6103e86106193660046149d3565b6118ef565b61041b611911565b610438610634366004614b77565b611917565b610438610647366004614e6b565b6119b5565b610654611aad565b6040516103f59594939291906153da565b6104386106733660046149d3565b611b40565b610406611bf9565b61041b611c1d565b6104386106963660046149d3565b611c41565b61045d6106a9366004614dc2565b611caa565b6106b6611cd3565b6040516103f59291906151f1565b6104386106d2366004614ce6565b611ce9565b6104386106e5366004614d29565b611d80565b6104386106f8366004614ac1565b611e48565b610406611eef565b610406611f13565b610715611f22565b6040516103f591906150d6565b610438610730366004614b77565b611f2c565b61041b611f93565b610745611f99565b6040516103f5999897969594939291906154a0565b610438610768366004614e13565b611fc0565b6103e8612051565b6103e8612061565b61078561213f565b6040516103f592919061535a565b6107a66107a1366004614dc2565b612160565b6040516103f59190615278565b61041b6121d1565b61041b6107c9366004614dc2565b612237565b610438612249565b6107de612303565b6040516103f59190615265565b610406612328565b610438610801366004614ca4565b61234c565b60055460ff1681565b601f546001600160a01b031681565b60006108286123a6565b90505b90565b7f000000000000000000000000100000000000000000000000000000000000000390565b600054600160b01b900460ff16806108745750600054600160a81b900460ff16155b15610893576108816123f9565b6005805460ff1916600117905561089e565b61089e60003661242e565b565b601e546001600160a01b031681565b600054600160b01b900460ff16806108d15750600054600160a81b900460ff16155b1561099a576108de6123f9565b60408051808201909152600e81526d05265776172642065706f636820360941b60208201528161092a5760405162461bcd60e51b81526004016109219190615265565b60405180910390fd5b507f00000000000000000000000000000000000000000000000000000000000000b4818161095457fe5b06600014604051806060016040528060278152602001615627602791399061098f5760405162461bcd60e51b81526004016109219190615265565b50601b8190556109a5565b6109a560003661242e565b50565b7f0000000000000000000000000000000000000000000000000000000062cf1e467f00000000000000000000000000000000000000000000000000000000000000b47f000000000000000000000000000000000000000000000000000000000000005a909192565b601b547f0000000000000000000000000000000000000000000000000000000062d9a23091565b600054600160b01b900460ff1680610a595750600054600160a81b900460ff16155b1561099a57610a666123f9565b610a718160016125b1565b6109a5565b600454606090819081908190600090610aa090600160c01b90046001600160401b03166001611487565b945094509450945094509091929394565b6007546001600160a01b031681565b600054600160b01b900460ff1680610ae25750600054600160a81b900460ff16155b1561099a57610aef6123f9565b60408051808201909152601e81527f566f746520706f77657220696e74657276616c206672616374696f6e20300000602082015281610b415760405162461bcd60e51b81526004016109219190615265565b50601c8190556109a5565b600054600160b01b900460ff1680610b6e5750600054600160a81b900460ff16155b15610b8b57610b7b6123f9565b610b86838383612630565b610b96565b610b9660003661242e565b505050565b6016546001600160a01b031690565b601d5490565b600054600160b01b900460ff1680610bd25750600054600160a81b900460ff16155b1561099a57610bdf6123f9565b602180546001600160a01b0319166001600160a01b0383161790556109a5565b602154600160a01b900460ff16606080610c176126b3565b8051909250806001600160401b0381118015610c3257600080fd5b50604051908082528060200260200182016040528015610c5c578160200160208202803683370190505b50915060005b81811015610cd75760136002016000858381518110610c7d57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900460ff16838281518110610cbf57fe5b91151560209283029190910190910152600101610c62565b5050909192565b6020546001600160a01b031681565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b600a54600b54600c54600d54600e54600f54601054601254601180546040805160208084028201810190925282815260009b8c9b8c9b8c9b8c9b8c9b8c9b60609b8d9b8c9b989a979996989597949693959294909360ff61010084048116949316929091859190830182828015610db257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610d94575b50505050509250995099509950995099509950995099509950995090919293949596979899565b6021546001600160a01b031681565b60008054600160a81b900460ff16610e0b576000546001600160a01b0316610828565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4b57600080fd5b505afa158015610e5f573d6000803e3d6000fd5b505050506040513d6020811015610e7557600080fd5b5051905090565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b158015610ec057600080fd5b505afa158015610ed4573d6000803e3d6000fd5b505050506040513d6020811015610eea57600080fd5b5051610f2d576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610f99576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b8054421015610fef576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156110895780601f1061105e57610100808354040283529160200191611089565b820191906000526020600020905b81548152906001019060200180831161106c57829003601f168201915b5050506001600160e01b03198616600090815260016020819052604082208281559495509092506110bd9150830182614799565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106111055780518252601f1990920191602091820191016110e6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611167576040519150601f19603f3d011682016040523d82523d6000602084013e61116c565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a16111cb81612734565b50505050565b601c5490565b60076001609c1b0181565b6111ea612751565b6001600160e01b03198116600090815260016020526040902054611255576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610b9690830182614799565b600581565b600054600160b01b900460ff16806112ec5750600054600160a81b900460ff16155b1561135c576112f96123f9565b60405163d0d552dd60e01b81526001600160a01b0383169063d0d552dd90611325908490600401614fe1565b600060405180830381600087803b15801561133f57600080fd5b505af1158015611353573d6000803e3d6000fd5b50505050611367565b61136760003661242e565b5050565b601854601954601a5460ff16909192565b6000336001600160a01b037f000000000000000000000000100000000000000000000000000000000000000216146113ef576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b60055460ff166114015750600061082b565b600854611415576114106127b0565b611481565b601a5460ff16801561142957504260195411155b15611436576114106128f4565b601a5460ff1615801561144b57504260095411155b1561147057611458612ee5565b611460613132565b6114686132be565b611410613415565b42601954116114815761148161355d565b50600190565b606080606080600060038054905087106040518060400160405280601081526020016f0e6e8c2e4e840d2dcc8caf040d0d2ced60831b815250906114de5760405162461bcd60e51b81526004016109219190615265565b5060035460009088880111156114f9576003548890036114fb565b865b9050806001600160401b038111801561151357600080fd5b5060405190808252806020026020018201604052801561153d578160200160208202803683370190505b509550806001600160401b038111801561155657600080fd5b50604051908082528060200260200182016040528015611580578160200160208202803683370190505b509450806001600160401b038111801561159957600080fd5b506040519080825280602002602001820160405280156115cd57816020015b60608152602001906001900390816115b85790505b509350806001600160401b03811180156115e657600080fd5b50604051908082528060200260200182016040528015611610578160200160208202803683370190505b50925060005b818110156117c65760006003828b018154811061162f57fe5b6000918252602080832090910154808352600290915260409091205489519192506001600160c01b03169089908490811061166657fe5b6020026020010181815250506002600082815260200190815260200160002060000160189054906101000a90046001600160401b03166001600160401b03168783815181106116b157fe5b602090810291909101810191909152600082815260028083526040918290208101805483516001821615610100026000190190911692909204601f810185900485028301850190935282825290929091908301828280156117535780601f1061172857610100808354040283529160200191611753565b820191906000526020600020905b81548152906001019060200180831161173657829003601f168201915b505050505086838151811061176457fe5b60200260200101819052506002600082815260200190815260200160002060010160009054906101000a90046001600160a01b03168583815181106117a557fe5b6001600160a01b039092166020928302919091019091015250600101611616565b50506004549497939650919450926001600160c01b0316919050565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f8101859004850286018501909652858552909491939290919083018282801561187e5780601f106118535761010080835404028352916020019161187e565b820191906000526020600020905b81548152906001019060200180831161186157829003601f168201915b5050505050905082565b600054600160b01b900460ff16806118aa5750600054600160a81b900460ff16155b15610b8b576118b76123f9565b60005b83518110156118e9576118e18482815181106118d257fe5b60200260200101518484612630565b6001016118ba565b50610b96565b6001600160a01b03811660009081526014602052604090205460ff165b919050565b601b5481565b600054600160b01b900460ff16806119395750600054600160a81b900460ff16155b1561099a576119466123f9565b60405163984626c360e01b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e9063984626c390611980906013908590600401615299565b60006040518083038186803b15801561199857600080fd5b505af41580156119ac573d6000803e3d6000fd5b505050506109a5565b600054600160b01b900460ff16806119d75750600054600160a81b900460ff16155b15611a98576119e46123f9565b6000881180156119f45750600087115b8015611a005750858510155b8015611a0e57506127108411155b8015611a1c57506127108311155b8015611a285750600082115b8015611a3657506005815111155b6040518060400160405280601381526020017211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b81525090611a805760405162461bcd60e51b81526004016109219190615265565b50611a93600a898989898989898961388c565b611aa3565b611aa360003661242e565b5050505050505050565b600080600080600080611abe6123a6565b9550507f0000000000000000000000000000000000000000000000000000000062cf1e467f00000000000000000000000000000000000000000000000000000000000000b4808702820195506001870102019250507f000000000000000000000000000000000000000000000000000000000000005a82019050429091929394565b600054600160a01b900460ff1615611b96576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000100000000000000000000000000000000000000281565b7f0000000000000000000000000000000000000000000000000000000062d9a23081565b600054600160b01b900460ff1680611c635750600054600160a81b900460ff16155b1561099a57611c706123f9565b604051635d9fe31360e01b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e90635d9fe313906119809060139085906004016152b2565b600080600080611cb985612160565b805160208201516040909201519097919650945092505050565b6016546017546001600160a01b03918216911682565b600054600160b01b900460ff1680611d0b5750600054600160a81b900460ff16155b1561135c57611d186123f9565b604051636904d3eb60e11b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e9063d209a7d690611d5490601390869086906004016152c9565b60006040518083038186803b158015611d6c57600080fd5b505af4158015611353573d6000803e3d6000fd5b611d88612751565b6001600160a01b0382166000908152601360209081526040918290205482518084019093526009835268139bdd08199bdd5b9960ba1b9183019190915260ff16611de55760405162461bcd60e51b81526004016109219190615265565b506001600160a01b03821660009081526015602052604090819020805460ff1916831515179055517f24462ede4d3e8e5a69fecec6290d42a311016ca752216d9a3d681e284791b7ac90611e3c908490849061520b565b60405180910390a15050565b611e50610ced565b6001600160a01b0316336001600160a01b031614611eac576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b611ee5611ee083836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250613a85565b613bb2565b6113678282613bd6565b7f000000000000000000000000000000000000000000000000000000000000000081565b6017546001600160a01b031690565b60606108286126b3565b600054600160b01b900460ff1680611f4e5750600054600160a81b900460ff16155b1561099a57611f5b6123f9565b60005b8151811015611f8d57611f85828281518110611f7657fe5b602002602001015160016125b1565b600101611f5e565b506109a5565b60095481565b600a54600b54600c54600d54600e54600f5460105460125460ff8082169161010090041689565b600054600160b01b900460ff1680611fe25750600054600160a81b900460ff16155b15610b8b57611fef6123f9565b600554604080518082019091526011815270105b1c9958591e481858dd1a5d985d1959607a1b60208201529060ff161561203c5760405162461bcd60e51b81526004016109219190615265565b50601d83905560088290556009819055610b96565b600054600160a81b900460ff1681565b6000336001600160a01b037f000000000000000000000000100000000000000000000000000000000000000216146120d4576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b602154600160a01b900460ff16612139576021805460ff60a01b1916600160a01b1790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc9061212990600190615188565b60405180910390a150600161082b565b50600090565b6004546001600160c01b03811690600160c01b90046001600160401b031682565b6121686147dd565b60085482106040518060400160405280602081526020017f5265776172642065706f6368206e6f7420696e697469616c697a656420796574815250906121c15760405162461bcd60e51b81526004016109219190615265565b506121cb82613d8c565b92915050565b6000600854600014156040518060400160405280602081526020017f5265776172642065706f6368206e6f7420696e697469616c697a6564207965748152509061222e5760405162461bcd60e51b81526004016109219190615265565b50610828613e91565b600061224282612160565b5192915050565b612251612751565b600054600160a81b900460ff16156122b0576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600b81526a233a39b7a6b0b730b3b2b960a91b602082015290565b7f000000000000000000000000100000000000000000000000000000000000000381565b612354612751565b6021805460ff60a01b1916600160a01b831515021790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc9061239b908390615188565b60405180910390a150565b60007f00000000000000000000000000000000000000000000000000000000000000b47f0000000000000000000000000000000000000000000000000000000062cf1e464203816123f357fe5b04905090565b600054600160b01b900460ff16156124265733301461241457fe5b6000805460ff60b01b1916905561089e565b61089e612751565b612436612751565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561247e57600080fd5b505afa158015612492573d6000803e3d6000fd5b505050506040513d60208110156124a857600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b0319861681526001602081815260409092208451815584830151805191945061252c939285019201906147fe565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b601a546040516306b8c18560e01b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e916306b8c185916125f791601391600a918891889160ff16906004016152f3565b60006040518083038186803b15801561260f57600080fd5b505af4158015612623573d6000803e3d6000fd5b5050505061136782613e9b565b601a5460405163169ffdc760e21b8152736d5d9dbbeff7e96c778ebc2f39756851fe6f624e91635a7ff71c9161267a91601391600a9189918991899160ff90911690600401615323565b60006040518083038186803b15801561269257600080fd5b505af41580156126a6573d6000803e3d6000fd5b50505050610b9683613e9b565b60165460408051635200305d60e11b815290516060926001600160a01b03169163a40060ba916004808301926000929190829003018186803b1580156126f857600080fd5b505afa15801561270c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108289190810190614bb1565b3d604051818101604052816000823e821561274d578181f35b8181fd5b612759610de8565b6001600160a01b0316336001600160a01b03161461089e576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b7f0000000000000000000000000000000000000000000000000000000062d9a230421061089e5760006127e16126b3565b80516040805160608101825243600019810182526020808301918252428385019081526008805460009081526006909352948220845181559251600180850191909155905160029093019290925583549091019092559293509091905b828110156128c65783818151811061285257fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b8152600401612889919061537c565b600060405180830381600087803b1580156128a357600080fd5b505af11580156128b7573d6000803e3d6000fd5b5050505080600101905061283e565b5050601b547f0000000000000000000000000000000000000000000000000000000062d9a230016009555050565b60006128fe6126b3565b8051909150801580159061291c5750602154600160a01b900460ff16155b15612dfb576007546000906001600160a01b03166129705781444260405160200161294892919061539e565b6040516020818303038152906040528051906020012060001c8161296857fe5b069050612a3e565b60007f00000000000000000000000010000000000000000000000000000000000000036001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156129cb57600080fd5b505afa1580156129df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a039190614dda565b9050828142604051602001612a1992919061539e565b6040516020818303038152906040528051906020012060001c81612a3957fe5b069150505b60608060008080805b87811015612be35760008882890181612a5c57fe5b06905060008a8281518110612a6d57fe5b6020908102919091018101516001600160a01b0381166000908152601490925260409091205490915060ff1615612ac3576001600160a01b03166000908152601460205260409020805460ff1916905550612bdb565b6018546040516340462a2d60e01b81526001600160a01b038316916340462a2d91612af49190891590600401615255565b600060405180830381600087803b158015612b0e57600080fd5b505af1925050508015612b4357506040513d6000823e601f3d908101601f19168201604052612b4091908101906149f6565b60015b612bae57612b4f615529565b80612b5a5750612b6a565b612b648282613fd8565b50612ba9565b612ba9816040518060400160405280601881526020017f6572722066696e616c697a652070726963652065706f63680000000000000000815250613fd8565b612bd8565b87158015612bbd575060008351115b15612bd45791995097509550600194509250828787875b5050505b50505b600101612a47565b506000612bee613e91565b90508215612d9257601e546018546001600160a01b039091169063a9b79e1790889088908890877f00000000000000000000000000000000000000000000000000000000000000b4886001612c4285614029565b03612c4c8b613d8c565b516040516001600160e01b031960e08c901b168152612c7699989796959493929190600401615059565b600060405180830381600087803b158015612c9057600080fd5b505af1925050508015612ca1575060015b612d8d57612cad615529565b80612cb85750612d0f565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c83601854604051612ceb929190614ff5565b60405180910390a1601e54612d09906001600160a01b031682614076565b50612d8d565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c82601854604051612d42929190614ff5565b60405180910390a1601e546040805180820190915260168152756572722064697374726962757465207265776172647360501b6020820152612d8d916001600160a01b031690614076565b612d9a565b612d9a61424f565b600780546001600160a01b0319166001600160a01b0384161790556040517f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad90612de79084908490614ff5565b60405180910390a150505050505050612ed7565b60005b81811015612e7c576000838281518110612e1457fe5b6020908102919091018101516001600160a01b0381166000908152601490925260409091205490915060ff1615612e69576001600160a01b03166000908152601460205260409020805460ff19169055612e74565b612e72816143d1565b505b600101612dfe565b50612e8561424f565b600780546001600160a01b03191690557f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad6000612ec0613e91565b604051612ece929190614ff5565b60405180910390a15b5050601a805460ff19169055565b6000612eef6126b3565b905060008151905060004290507f00000000000000000000000010000000000000000000000000000000000000036001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f5557600080fd5b505afa158015612f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8d9190614dda565b604051910190612fa190829060200161537c565b6040516020818303038152906040528051906020012060001c90506000601c54612fd1612fcc613e91565b613d8c565b60200151430381612fde57fe5b04905080612fea575060015b6000818381612ff557fe5b06905080613001575060015b60408051606081018252438381038252602080830191825242838501908152600880546000908152600690935294822084518155925160018085019190915590516002909301929092558354909101909255905b858110156130de5786818151811061306957fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b81526004016130a0919061537c565b600060405180830381600087803b1580156130ba57600080fd5b505af11580156130ce573d6000803e3d6000fd5b5050600190920191506130559050565b50805160208201516040517f1813f880dc24666c8b69c9d771a487ea620a27fde1514be3112847056c0c53229261311692909161539e565b60405180910390a15050601b5460098054909101905550505050565b600061313c613e91565b60105490915042035b81601d54108015613167575080613160601d54600101613d8c565b6040015111155b1561136757601e54601d54604051636b60edf760e11b81526001600160a01b039092169163d6c1dbee9161319d9160040161537c565b600060405180830381600087803b1580156131b757600080fd5b505af19250505080156131c8575060015b6132b0576131d4615529565b806131df5750613234565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d601d54604051613210919061537c565b60405180910390a1601e5461322e906001600160a01b031682614076565b50611367565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d601d54604051613265919061537c565b60405180910390a1601e54604080518082019091526011815270195c9c8818db1bdcd948195e1c1a5c9959607a1b60208201526132ab916001600160a01b031690614076565b611367565b601d80546001019055613145565b60006132cb601d54613d8c565b5160205460405163cbc31cf760e01b81529192506001600160a01b03169063cbc31cf7906132fd90849060040161537c565b600060405180830381600087803b15801561331757600080fd5b505af1925050508015613328575060015b6109a557613334615529565b8061333f5750613392565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d8260405161336e919061537c565b60405180910390a160205461338c906001600160a01b031682614076565b50610a71565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d816040516133c1919061537c565b60405180910390a1610a71602060009054906101000a90046001600160a01b0316604051806040016040528060158152602001746572722073657420636c65616e757020626c6f636b60581b815250614076565b6021546001600160a01b03161561089e576000613430613e91565b9050602160009054906101000a90046001600160a01b03166001600160a01b03166321eb1a956040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561348257600080fd5b505af1925050508015613493575060015b6109a55761349f615529565b806134aa57506134f7565b7ff7c7d6681321cc290eb89e8c96dba504436073b8bb277945cc32177e5181dd84826040516134d9919061537c565b60405180910390a160215461338c906001600160a01b031682614076565b7ff7c7d6681321cc290eb89e8c96dba504436073b8bb277945cc32177e5181dd8481604051613526919061537c565b60405180910390a160215460408051606081019091526022808252610a71926001600160a01b031691906156056020830139614076565b60125460ff16156135e857604051639ec2b58160e01b81526001600160a01b037f00000000000000000000000010000000000000000000000000000000000000031690639ec2b581906135b5906011906004016150c3565b600060405180830381600087803b1580156135cf57600080fd5b505af11580156135e3573d6000803e3d6000fd5b505050505b60006135f26126b3565b8051909150600081158015906136125750602154600160a01b900460ff16155b156136ab576000613624612fcc613e91565b51601f546040516237b08960e41b81529192506001600160a01b03169063037b08909061365590849060040161537c565b602060405180830381600087803b15801561366f57600080fd5b505af1158015613683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a79190614dda565b9150505b60005b828110156138515760008482815181106136c457fe5b602090810291909101015160125490915060ff161561375757600a54600b54600c54600d54600e54600f5460405163f7dba1f560e01b81526001600160a01b0388169663f7dba1f5966137249691959094919390926011906004016153fd565b600060405180830381600087803b15801561373e57600080fd5b505af1158015613752573d6000803e3d6000fd5b505050505b806001600160a01b031663f670ebe384602160149054906101000a900460ff168061379a57506001600160a01b03841660009081526015602052604090205460ff165b6040518363ffffffff1660e01b81526004016137b7929190615255565b600060405180830381600087803b1580156137d157600080fd5b505af19250505080156137e2575060015b613848576137ee615529565b806137f95750613809565b613803828261446d565b50613848565b613848816040518060400160405280601981526020017f65727220696e69742065706f636820666f722072657665616c0000000000000081525061446d565b506001016136ae565b506012805460ff1916905560006138666123a6565b601881905590506138768161467e565b6019555050601a805460ff191660011790555050565b885488146138a75760088901805460ff191660011790558789555b868960010154146138ca5760088901805460ff1916600190811790915589018790555b858960020154146138ec5760088901805460ff19166001179055600289018690555b8489600301541461390e5760088901805460ff19166001179055600389018590555b838960040154146139305760088901805460ff19166001179055600489018490555b828960050154146139525760088901805460ff19166001179055600589018390555b818960060154146139745760088901805460ff19166001179055600689018290555b805160078a0154146139aa5780516139959060078b0190602084019061488a565b5060088901805460ff19166001179055613a69565b60005b8151811015613a67578181815181106139c257fe5b60200260200101516001600160a01b03168a60070182815481106139e257fe5b6000918252602090912001546001600160a01b031614613a5f5760088a01805460ff191660011790558151829082908110613a1957fe5b60200260200101518a6007018281548110613a3057fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6001016139ad565b505b5050506008909501805461ff0019166101001790555050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b83811015613ac9578181015183820152602001613ab1565b50505050905090810190601f168015613af65780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b8651811015613b5e57868181518110613b2c57fe5b6020026020010151831415613b5657858181518110613b4757fe5b60200260200101519150613b5e565b600101613b17565b506001600160a01b038116613ba9576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b613c0a828260405180604001604052806011815260200170233a39b7a932bbb0b93226b0b730b3b2b960791b815250613a85565b601e60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613c59828260405180604001604052806006815260200165537570706c7960d01b815250613a85565b601f60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613cbf82826040518060400160405280601981526020017f436c65616e7570426c6f636b4e756d6265724d616e6167657200000000000000815250613a85565b602060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613d1482826040518060400160405280600c81526020016b4674736f526567697374727960a01b815250613a85565b601680546001600160a01b0319166001600160a01b039290921691909117905560408051808201909152601081526f2b37ba32b92bb434ba32b634b9ba32b960811b6020820152613d689083908390613a85565b601780546001600160a01b0319166001600160a01b03929092169190911790555050565b613d946147dd565b50600081815260066020908152604091829020825160608101845281548152600182015492810192909252600201549181018290529061190c5760008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a795f409866040518263ffffffff1660e01b8152600401613e1f919061537c565b60606040518083038186803b158015613e3757600080fd5b505afa158015613e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6f9190614e3e565b6040805160608101825293845260208401929092529082015295945050505050565b6008546000190190565b604051630bc29bcf60e21b81526001600160a01b03821690632f0a6f3c90613f2b907f0000000000000000000000000000000000000000000000000000000062cf1e46907f00000000000000000000000000000000000000000000000000000000000000b4907f000000000000000000000000000000000000000000000000000000000000005a906004016153c4565b600060405180830381600087803b158015613f4557600080fd5b505af1158015613f59573d6000803e3d6000fd5b505050506008546000146109a557806001600160a01b031663e536f396613f81612fcc613e91565b516040516001600160e01b031960e084901b168152613fa3919060040161537c565b600060405180830381600087803b158015613fbd57600080fd5b505af1158015613fd1573d6000803e3d6000fd5b5050505050565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b88182601854600160405161400e93929190615226565b60405180910390a16140208282614076565b611367826143d1565b7f0000000000000000000000000000000000000000000000000000000062cf1e46600182017f00000000000000000000000000000000000000000000000000000000000000b40201919050565b6000828260405160200161408b92919061500e565b60408051601f198184030181528282528051602091820120600081815260029092529190208054436001600160c01b038181166001600160401b03600160c01b80860482166001019091160291909316176001600160c01b031916919091179091559092507f1a601cf5e0efbd558b2778b7389af04741d1c49bcab104c40daa2da1945936179161411f9186918690615032565b60405180910390a1600480546001600160c01b0319811660016001600160c01b03928316810190921617909155600082815260026020526040902054600160c01b90046001600160401b031611156141775750611367565b6003805460018082019092557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01829055600082815260026020818152604090922092830180546001600160a01b0319166001600160a01b03881617905584516141e793909101918501906147fe565b50600354600091825260026020526040909120600101805467ffffffffffffffff60a01b1916600160a01b6000199093016001600160401b0390811684029190911791829055600480546001600160c01b03169390920416600160c01b029190911790555050565b601e546018546001600160a01b03909116906367dcac53907f00000000000000000000000000000000000000000000000000000000000000b4600161429383614029565b036040518463ffffffff1660e01b81526004016142b2939291906153c4565b600060405180830381600087803b1580156142cc57600080fd5b505af19250505080156142dd575060015b61089e576142e9615529565b806142f45750614349565b7f8eb60f903ef61e0e490d7d7ba6e5b85cd949ebece7a5e5b3346eb046c041413f601854604051614325919061537c565b60405180910390a1601e54614343906001600160a01b031682614076565b506143cc565b7f8eb60f903ef61e0e490d7d7ba6e5b85cd949ebece7a5e5b3346eb046c041413f60185460405161437a919061537c565b60405180910390a1601e5460408051808201909152601b81527f6572722061636372756520756e6561726e65642072657761726473000000000060208201526143cc916001600160a01b031690614076565b61089e565b60185460405163257ea88160e11b81526001600160a01b03831691634afd5102916143ff919060040161537c565b600060405180830381600087803b15801561441957600080fd5b505af192505050801561442a575060015b6109a557614436615529565b80614441575061444b565b61338c82826146ed565b610a718160405180606001604052806021815260200161564e602191396146ed565b7f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462826144976123a6565b6040516144a5929190614ff5565b60405180910390a16144b78282614076565b602154600160a01b900460ff16806144e757506001600160a01b03821660009081526015602052604090205460ff165b15614514576001600160a01b0382166000908152601460205260409020805460ff19166001179055611367565b60405163f670ebe360e01b81526001600160a01b0383169063f670ebe39061454490600090600190600401615255565b600060405180830381600087803b15801561455e57600080fd5b505af192505050801561456f575060015b6113675761457b615529565b8061458657506145f9565b6001600160a01b0383166000908152601460205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462836145d36123a6565b6040516145e1929190614ff5565b60405180910390a16145f38382614076565b506132ab565b6001600160a01b0382166000908152601460205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462826146466123a6565b604051614654929190614ff5565b60405180910390a16132ab826040518060600160405280602281526020016155e360229139614076565b7f0000000000000000000000000000000000000000000000000000000062cf1e46600182017f00000000000000000000000000000000000000000000000000000000000000b402017f000000000000000000000000000000000000000000000000000000000000005a01919050565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b88182601854600260405161472393929190615226565b60405180910390a16147358282614076565b60185460405163974d7a6b60e01b81526001600160a01b0384169163974d7a6b91614763919060040161537c565b600060405180830381600087803b15801561477d57600080fd5b505af1158015614791573d6000803e3d6000fd5b505050505050565b50805460018160011615610100020316600290046000825580601f106147bf57506109a5565b601f0160209004906000526020600020908101906109a591906148df565b60405180606001604052806000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282614834576000855561487a565b82601f1061484d57805160ff191683800117855561487a565b8280016001018555821561487a579182015b8281111561487a57825182559160200191906001019061485f565b506148869291506148df565b5090565b82805482825590600052602060002090810192821561487a579160200282015b8281111561487a57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906148aa565b5b8082111561488657600081556001016148e0565b600082601f830112614904578081fd5b8135602061491961491483615506565b6154e3565b8281528181019085830183850287018401881015614935578586fd5b855b8581101561495c57813561494a816155cd565b84529284019290840190600101614937565b5090979650505050505050565b600082601f830112614979578081fd5b8151602061498961491483615506565b82815281810190858301838502870184018810156149a5578586fd5b855b8581101561495c578151845292840192908401906001016149a7565b8035801515811461190c57600080fd5b6000602082840312156149e4578081fd5b81356149ef816155cd565b9392505050565b600080600060608486031215614a0a578182fd5b83516001600160401b0380821115614a20578384fd5b818601915086601f830112614a33578384fd5b81516020614a4361491483615506565b82815281810190858301838502870184018c1015614a5f578889fd5b8896505b84871015614a8a578051614a76816155cd565b835260019690960195918301918301614a63565b5091890151919750909350505080821115614aa3578384fd5b50614ab086828701614969565b925050604084015190509250925092565b60008060408385031215614ad3578182fd5b82356001600160401b0380821115614ae9578384fd5b818501915085601f830112614afc578384fd5b81356020614b0c61491483615506565b82815281810190858301838502870184018b1015614b28578889fd5b8896505b84871015614b4a578035835260019690960195918301918301614b2c565b5096505086013592505080821115614b60578283fd5b50614b6d858286016148f4565b9150509250929050565b600060208284031215614b88578081fd5b81356001600160401b03811115614b9d578182fd5b614ba9848285016148f4565b949350505050565b60006020808385031215614bc3578182fd5b82516001600160401b03811115614bd8578283fd5b8301601f81018513614be8578283fd5b8051614bf661491482615506565b8181528381019083850185840285018601891015614c12578687fd5b8694505b83851015614c3d578051614c29816155cd565b835260019490940193918501918501614c16565b50979650505050505050565b600080600060608486031215614c5d578081fd5b83356001600160401b03811115614c72578182fd5b614c7e868287016148f4565b935050614c8d602085016149c3565b9150614c9b604085016149c3565b90509250925092565b600060208284031215614cb5578081fd5b6149ef826149c3565b600060208284031215614ccf578081fd5b81356001600160e01b0319811681146149ef578182fd5b60008060408385031215614cf8578182fd5b8235614d03816155cd565b915060208301356001600160401b03811115614d1d578182fd5b614b6d858286016148f4565b60008060408385031215614d3b578182fd5b8235614d46816155cd565b9150614d54602084016149c3565b90509250929050565b600080600060608486031215614d71578081fd5b8335614d7c816155cd565b9250614c8d602085016149c3565b60008060408385031215614d9c578182fd5b8235614da7816155cd565b91506020830135614db7816155cd565b809150509250929050565b600060208284031215614dd3578081fd5b5035919050565b600060208284031215614deb578081fd5b5051919050565b60008060408385031215614e04578182fd5b50508035926020909101359150565b600080600060608486031215614e27578081fd5b505081359360208301359350604090920135919050565b600080600060608486031215614e52578081fd5b8351925060208401519150604084015190509250925092565b600080600080600080600080610100898b031215614e87578586fd5b883597506020890135965060408901359550606089013594506080890135935060a0890135925060c0890135915060e08901356001600160401b03811115614ecd578182fd5b614ed98b828c016148f4565b9150509295985092959890939650565b6000815180845260208085019450808401835b83811015614f215781516001600160a01b031687529582019590820190600101614efc565b509495945050505050565b6000815480845260208085019450838352808320835b83811015614f215781546001600160a01b031687529582019560019182019101614f42565b6000815180845260208085019450808401835b83811015614f2157815187529582019590820190600101614f7a565b60008151808452815b81811015614fbb57602081850181015186830182015201614f9f565b81811115614fcc5782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0383168152604060208201819052600090614ba990830184614f96565b600060018060a01b038516825283602083015260606040830152613ba96060830184614f96565b600061012080835261506d8184018d614ee9565b90508281036020840152615081818c614f67565b604084019a909a52505060608101969096526001600160a01b0394909416608086015260a085019290925260c084015260e08301526101009091015292915050565b6000602082526149ef6020830184614f2c565b6000602082526149ef6020830184614ee9565b600060a082526150fc60a0830188614f67565b60208382038185015261510f8289614f67565b848103604086015287518082529092508183019082810284018301838a01865b8381101561515d57601f1987840301855261514b838351614f96565b9486019492509085019060010161512f565b50508681036060880152615171818a614ee9565b955050505050508260808301529695505050505050565b901515815260200190565b6000841515825260206060818401526151af6060840186614ee9565b8381036040850152845180825282860191830190845b818110156151e35783511515835292840192918401916001016151c5565b509098975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b038416815260208101839052606081016006831061524757fe5b826040830152949350505050565b9182521515602082015260400190565b6000602082526149ef6020830184614f96565b81518152602080830151908201526040918201519181019190915260600190565b600083825260406020830152614ba96040830184614ee9565b9182526001600160a01b0316602082015260400190565b8381526001600160a01b0383166020820152606060408201819052600090613ba990830184614ee9565b94855260208501939093526001600160a01b03919091166040840152151560608301521515608082015260a00190565b95865260208601949094526001600160a01b039290921660408501521515606084015215156080830152151560a082015260c00190565b6001600160c01b039290921682526001600160401b0316602082015260400190565b90815260200190565b600083825260406020830152614ba96040830184614f96565b918252602082015260400190565b92835260208301919091521515604082015260600190565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b60008882528760208301528660408301528560608301528460808301528360a083015260e060c083015261543460e0830184614f2c565b9998505050505050505050565b60006101408c83528b60208401528a60408401528960608401528860808401528760a08401528660c08401528060e084015261547f81840187614ee9565b94151561010084015250509015156101209091015298975050505050505050565b988952602089019790975260408801959095526060870193909352608086019190915260a085015260c0840152151560e083015215156101008201526101200190565b6040518181016001600160401b03811182821017156154fe57fe5b604052919050565b60006001600160401b0382111561551957fe5b5060209081020190565b60e01c90565b600060443d10156155395761082b565b600481823e6308c379a061554d8251615523565b146155575761082b565b6040513d600319016004823e80513d6001600160401b038160248401118184111715615586575050505061082b565b828401925082519150808211156155a0575050505061082b565b503d830160208284010111156155b85750505061082b565b601f01601f1916810160200160405291505090565b6001600160a01b03811681146109a557600080fdfe6572722066616c6c6261636b20696e69742065706f636820666f722072657665616c6572722063616c6c696e672075706461746541637469766556616c696461746f72735265776172642065706f6368206475726174696f6e20636f6e646974696f6e20696e76616c69646572722066616c6c6261636b2066696e616c697a652070726963652065706f6368a2646970667358221220ecf6e57ae61845a2bd7a19441a33f0535c5296d449ac52253f962fd65261ce0a64736f6c63430007060033