false
false
0

Contract Address Details

0xcD099A11ecd4b02aFF5F17eC46242a9a7cfdA527

Contract Name
FtsoRegistry
Creator
0x4598a6–d10d29 at 0x72b661–a71d95
Balance
0 FLR ( )
Tokens
Fetching tokens...
Transactions
2 Transactions
Transfers
0 Transfers
Gas Used
52,350
Last Balance Update
21666820
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
FtsoRegistry




Optimization enabled
true
Compiler version
v0.7.6+commit.7338295f




Optimization runs
200
Verified at
2022-07-13T21:18:12.582856Z

Constructor Arguments

0000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d29000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b

Arg [0] (address) : 0x4598a6c05910ab914f0cbaaca1911cd337d10d29
Arg [1] (address) : 0xbaf89d873d198ff78e72d2745b01cba3c6e5be6b

              

./contracts/utils/implementation/FtsoRegistry.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma abicoder v2;


import "../interface/IIFtsoRegistry.sol";
import "../../addressUpdater/implementation/AddressUpdatable.sol";
import "../../ftso/interface/IIFtsoManager.sol";
import "../../governance/implementation/Governed.sol";

/**
 * @title A contract for FTSO registry
 */
contract FtsoRegistry is IIFtsoRegistry, Governed, AddressUpdatable { 

    // constants
    uint256 internal constant MAX_HISTORY_LENGTH = 5;

    // errors
    string internal constant ERR_TOKEN_NOT_SUPPORTED = "FTSO index not supported";
    string internal constant ERR_FTSO_MANAGER_ONLY = "FTSO manager only";

    // storage 
    IIFtso[MAX_HISTORY_LENGTH][] private ftsoHistory;

    // addresses
    // This address has to be set in deploy phase
    IIFtsoManager public ftsoManager;

    modifier onlyFtsoManager () {
        require (msg.sender == address(ftsoManager), ERR_FTSO_MANAGER_ONLY);
        _;
    }

    constructor(
        address _governance,
        address _addressUpdater
    )
        Governed(_governance) AddressUpdatable(_addressUpdater)
    {
        /* empty block */
    }

    /**
     * @notice Update current active FTSO contracts mapping
     * @param _ftsoContract new target FTSO contract
     */
    function addFtso(IIFtso _ftsoContract) external override onlyFtsoManager returns(uint256 _ftsoIndex) {
        uint256 len = ftsoHistory.length;
        string memory _symbol = _ftsoContract.symbol();
        bytes32 _encodedSymbol = keccak256(abi.encode(_symbol));
        _ftsoIndex = 0;
        // Iterate over supported symbol array
        for ( ; _ftsoIndex < len; _ftsoIndex++) {
            // Deletion of symbols leaves an empty address "hole", so the address might be zero
            IIFtso current = ftsoHistory[_ftsoIndex][0];
            if (address(current) == address(0)) {
                continue;
            }
            if (_encodedSymbol == keccak256(abi.encode(current.symbol()))) {
                break;
            }
        }
        // ftso with the same symbol is not yet in history array, add it
        if (_ftsoIndex == len) {
            ftsoHistory.push();
        } else {
            // Shift history
            _shiftHistory(_ftsoIndex);
        }
        ftsoHistory[_ftsoIndex][0] = _ftsoContract;
    }

    /**
     * Removes the ftso at specified index and keeps part of the history
     * @dev Reverts if the provided index is unsupported
     * @param _ftso ftso to remove
     */
    function removeFtso(IIFtso _ftso) external override onlyFtsoManager {
        bytes32 _encodedSymbol = keccak256(abi.encode(_ftso.symbol()));
        uint256 len = ftsoHistory.length;
        for (uint256 i = 0; i < len; ++i) {
            IIFtso current = ftsoHistory[i][0];
            if (address(current) == address(0)) {
                continue;
            }
            // Removal behaves the same as setting null value as current
            if (_encodedSymbol == keccak256(abi.encode(current.symbol()))) {
                _shiftHistory(i);
                ftsoHistory[i][0] = IIFtso(address(0));
                return;
            }

        }

        revert(ERR_TOKEN_NOT_SUPPORTED);
    }

    /**
     * @dev Reverts if unsupported index is passed
     * @return _activeFtso FTSO contract for provided index
     */
    function getFtso(uint256 _assetIndex) external view override returns(IIFtso _activeFtso) {
        return _getFtso(_assetIndex);
    }

    /**
     * @dev Reverts if unsupported symbol is passed
     * @return _activeFtso FTSO contract for provided symbol
     */
    function getFtsoBySymbol(string memory _symbol) external view override returns(IIFtso _activeFtso) {
        return _getFtso(_getFtsoIndex(_symbol));
    }

    /**
     * @notice Public view function to get the price of active FTSO for given asset index
     * @dev Reverts if unsupported index is passed
     * @return _price current price of asset in USD
     * @return _timestamp timestamp for when this price was updated
     */
    function getCurrentPrice(uint256 _assetIndex) external view override 
        returns(uint256 _price, uint256 _timestamp) 
    {
        return _getFtso(_assetIndex).getCurrentPrice();
    }

    function getCurrentPrice(string memory _symbol) external view override 
        returns(uint256 _price, uint256 _timestamp) 
    {
        return _getFtso(_getFtsoIndex(_symbol)).getCurrentPrice();
    }
    

    /**
     * @return _supportedIndices the array of all active FTSO indices in increasing order. 
     * Active FTSOs are ones that currently receive price feeds.
     */
    function getSupportedIndices() external view override returns(uint256[] memory _supportedIndices) {
        return _getSupportedIndices();
    }

    /**
     * @return _supportedSymbols the array of all active FTSO symbols in increasing order. 
     * Active FTSOs are ones that currently receive price feeds.
     */
    function getSupportedSymbols() external view override returns(string[] memory _supportedSymbols) {
        uint256[] memory _supportedIndices = _getSupportedIndices();
        uint256 len = _supportedIndices.length;
        _supportedSymbols = new string[](len);
        while (len > 0) {
            --len;
            IIFtso ftso = ftsoHistory[_supportedIndices[len]][0];
            _supportedSymbols[len] = ftso.symbol();
        }
    }

    /**
     * @notice Get array of all supported indices and corresponding FTSOs
     * @return _supportedIndices the array of all supported indices
     * @return _ftsos the array of all supported ftsos
     */
    function getSupportedIndicesAndFtsos() external view override
        returns(uint256[] memory _supportedIndices, IIFtso[] memory _ftsos)
    {
        _supportedIndices = _getSupportedIndices();
        uint256 len = _supportedIndices.length;
        _ftsos = new IIFtso[](len);
        while (len > 0) {
            --len;
            _ftsos[len] = ftsoHistory[_supportedIndices[len]][0];
        }
    }

    /**
     * @notice Get array of all supported symbols and corresponding FTSOs
     * @return _supportedSymbols the array of all supported symbols
     * @return _ftsos the array of all supported ftsos
     */
    function getSupportedSymbolsAndFtsos() external view override
        returns(string[] memory _supportedSymbols, IIFtso[] memory _ftsos)
    {
        uint256[] memory _supportedIndices = _getSupportedIndices();
        uint256 len = _supportedIndices.length;
        _ftsos = new IIFtso[](len);
        _supportedSymbols = new string[](len);
        while (len > 0) {
            --len;
            _ftsos[len] = ftsoHistory[_supportedIndices[len]][0];
            _supportedSymbols[len] = _ftsos[len].symbol();
        }
    }

    /**
     * @notice Get array of all supported indices and corresponding symbols
     * @return _supportedIndices the array of all supported indices
     * @return _supportedSymbols the array of all supported symbols
     */
    function getSupportedIndicesAndSymbols() external view override
        returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols) 
    {
        _supportedIndices = _getSupportedIndices();
        uint256 len = _supportedIndices.length;
        _supportedSymbols = new string[](len);
        while (len > 0) {
            --len;
            IIFtso ftso = ftsoHistory[_supportedIndices[len]][0];
            _supportedSymbols[len] = ftso.symbol();
        }
    }

    /**
     * @notice Get array of all supported indices, corresponding symbols and FTSOs
     * @return _supportedIndices the array of all supported indices
     * @return _supportedSymbols the array of all supported symbols
     * @return _ftsos the array of all supported ftsos
     */
    function getSupportedIndicesSymbolsAndFtsos() external view override
        returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols, IIFtso[] memory _ftsos)
    {
        _supportedIndices = _getSupportedIndices();
        uint256 len = _supportedIndices.length;
        _ftsos = new IIFtso[](len);
        _supportedSymbols = new string[](len);
        while (len > 0) {
            --len;
            _ftsos[len] = ftsoHistory[_supportedIndices[len]][0];
            _supportedSymbols[len] = _ftsos[len].symbol();
        }
    }

    /**
     * @notice Get array of all FTSO contracts for all supported asset indices. 
     * The index of FTSO in returned array does not necessarily correspond to _assetIndex
     * Due to deletion, some indices might be unsupported. 
     * @dev See `getSupportedIndicesAndFtsos` for pair of correct indices and `getAllFtsos` 
     * for FTSOs at valid indices but with possible "null" holes.
     * @return _ftsos the array of all supported FTSOs
     */
    function getSupportedFtsos() external view override returns(IIFtso[] memory _ftsos) {
        uint256[] memory supportedIndices = _getSupportedIndices();
        uint256 len = supportedIndices.length;
        _ftsos = new IIFtso[](len);
        while (len > 0) {
            --len;
            _ftsos[len] = ftsoHistory[supportedIndices[len]][0];
        }
    }

    /**
     * @notice Get the active FTSOs for given indices
     * @return _ftsos the array of FTSOs
     */
    function getFtsos(uint256[] memory _assetIndices) external view override returns(IFtsoGenesis[] memory _ftsos) {
        uint256 ftsoLength = ftsoHistory.length;
        uint256 len = _assetIndices.length;
        _ftsos = new IFtsoGenesis[](len);
        while (len > 0) {
            --len;
            uint256 assetIndex = _assetIndices[len];
            require(assetIndex < ftsoLength, ERR_TOKEN_NOT_SUPPORTED);
            _ftsos[len] = ftsoHistory[assetIndex][0];
            if (address(_ftsos[len]) == address(0)) {
                // Invalid index, revert if address is zero address
                revert(ERR_TOKEN_NOT_SUPPORTED);
            }
        }
    }

    /**
     * @notice Get array of all FTSO contracts for all supported asset indices
     * @return _ftsos the array of all FTSOs
     * @dev Return value might contain uninitialized FTSOS at zero address. 
     */
    function getAllFtsos() external view returns(IIFtso[] memory _ftsos) {
        uint256 len = ftsoHistory.length;
        IIFtso[] memory ftsos = new IIFtso[](len);
        while (len > 0) {
            --len;
            ftsos[len] = ftsoHistory[len][0];
        }
        return ftsos;
    }

    /**
     * @notice Get the history of FTSOs for given index
     * @dev If there are less then MAX_HISTORY_LENGTH the remaining addresses will be 0 addresses
     * @param _assetIndex asset index
     * @return _ftsoAddressHistory the history of FTSOs contract for provided index
     */
    function getFtsoHistory(uint256 _assetIndex) external view 
        returns(IIFtso[MAX_HISTORY_LENGTH] memory _ftsoAddressHistory) 
    {
        require(_assetIndex < ftsoHistory.length && 
                address(ftsoHistory[_assetIndex][0]) != address(0), ERR_TOKEN_NOT_SUPPORTED);
        return ftsoHistory[_assetIndex];
    }

    function getFtsoIndex(string memory _symbol) external view override returns (uint256 _assetIndex) {
        return _getFtsoIndex(_symbol);
    }

    function getFtsoSymbol(uint256 _assetIndex) external view override returns (string memory _symbol) {
        return _getFtso(_assetIndex).symbol();
    }

    /**
     * @notice Implementation of the AddressUpdatable abstract method.
     */
    function _updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
    )
        internal override
    {
        ftsoManager = IIFtsoManager(_getContractAddress(_contractNameHashes, _contractAddresses, "FtsoManager"));
    }

    /**
     * @notice Shift the FTSOs history by one so the FTSO at index 0 can be overwritten
     * @dev Internal helper function
     */
    function _shiftHistory(uint256 _assetIndex) internal {
        for (uint256 i = MAX_HISTORY_LENGTH-1; i > 0; i--) {
            ftsoHistory[_assetIndex][i] = ftsoHistory[_assetIndex][i-1];
        }
    }

    function _getFtsoIndex(string memory _symbol) private view returns (uint256 _assetIndex) {
        bytes32 _encodedSymbol = keccak256(abi.encode(_symbol));
        uint256 len = ftsoHistory.length;
        for (uint256 i = 0; i < len; ++i) {
            IIFtso current = ftsoHistory[i][0];
            if (address(current) == address(0)) {
                continue;
            }
            if (_encodedSymbol == keccak256(abi.encode(current.symbol()))) {
                return i;
            }
        }

        revert(ERR_TOKEN_NOT_SUPPORTED); 
    }

    /**
     * @notice Get the active FTSO for given index
     * @dev Internal get ftso function so it can be used within other methods
     */
    function _getFtso(uint256 _assetIndex) private view returns(IIFtso _activeFtso) {
        require(_assetIndex < ftsoHistory.length, ERR_TOKEN_NOT_SUPPORTED);

        IIFtso ftso = ftsoHistory[_assetIndex][0];
        if (address(ftso) == address(0)) {
            // Invalid index, revert if address is zero address
            revert(ERR_TOKEN_NOT_SUPPORTED);
        }
        _activeFtso = ftso;
    }

    function _getSupportedIndices() private view 
        returns(uint256[] memory _supportedIndices) 
    {
        uint256 len = ftsoHistory.length;
        uint256[] memory supportedIndices = new uint256[](len);
        address zeroAddress = address(0);
        uint256 taken = 0;
        for (uint256 i = 0; i < len; ++i) {
            if (address(ftsoHistory[i][0]) != zeroAddress) {
                supportedIndices[taken] = i;
                ++taken;
            }
        }
        _supportedIndices = new uint256[](taken);
        while (taken > 0) {
            --taken;
            _supportedIndices[taken] = supportedIndices[taken];
        }
        return _supportedIndices;
    }
}
        

./contracts/addressUpdater/implementation/AddressUpdatable.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

import "../interface/IIAddressUpdatable.sol";


abstract contract AddressUpdatable is IIAddressUpdatable {

    // https://docs.soliditylang.org/en/v0.8.7/contracts.html#constant-and-immutable-state-variables
    // No storage slot is allocated
    bytes32 internal constant ADDRESS_STORAGE_POSITION = 
        keccak256("flare.diamond.AddressUpdatable.ADDRESS_STORAGE_POSITION");

    modifier onlyAddressUpdater() {
        require (msg.sender == getAddressUpdater(), "only address updater");
        _;
    }

    constructor(address _addressUpdater) {
        setAddressUpdaterValue(_addressUpdater);
    }

    function getAddressUpdater() public view returns (address _addressUpdater) {
        // Only direct constants are allowed in inline assembly, so we assign it here
        bytes32 position = ADDRESS_STORAGE_POSITION;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            _addressUpdater := sload(position)
        }
    }

    /**
     * @notice external method called from AddressUpdater only
     */
    function updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
    )
        external override
        onlyAddressUpdater
    {
        // update addressUpdater address
        setAddressUpdaterValue(_getContractAddress(_contractNameHashes, _contractAddresses, "AddressUpdater"));
        // update all other addresses
        _updateContractAddresses(_contractNameHashes, _contractAddresses);
    }

    /**
     * @notice virtual method that a contract extending AddressUpdatable must implement
     */
    function _updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
    ) internal virtual;

    /**
     * @notice helper method to get contract address
     * @dev it reverts if contract name does not exist
     */
    function _getContractAddress(
        bytes32[] memory _nameHashes,
        address[] memory _addresses,
        string memory _nameToFind
    )
        internal pure
        returns(address)
    {
        bytes32 nameHash = keccak256(abi.encode(_nameToFind));
        address a = address(0);
        for (uint256 i = 0; i < _nameHashes.length; i++) {
            if (nameHash == _nameHashes[i]) {
                a = _addresses[i];
                break;
            }
        }
        require(a != address(0), "address zero");
        return a;
    }

    function setAddressUpdaterValue(address _addressUpdater) internal {
        // Only direct constants are allowed in inline assembly, so we assign it here
        bytes32 position = ADDRESS_STORAGE_POSITION;
        // solhint-disable-next-line no-inline-assembly  
        assembly {
            sstore(position, _addressUpdater)
        }
    }
}
          

./contracts/addressUpdater/interface/IIAddressUpdatable.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;


interface IIAddressUpdatable {
    /**
     * @notice Updates contract addresses - should be called only from AddressUpdater contract
     * @param _contractNameHashes       list of keccak256(abi.encode(...)) contract names
     * @param _contractAddresses        list of contract addresses corresponding to the contract names
     */
    function updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
        ) external;
}
          

./contracts/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/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/genesis/interface/IFlareDaemonize.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;


/// Any contracts that want to recieve a trigger from Flare daemon should 
///     implement IFlareDaemonize
interface IFlareDaemonize {

    /// Implement this function for recieving a trigger from FlareDaemon.
    function daemonize() external returns (bool);
    
    /// This function will be called after an error is caught in daemonize().
    /// It will switch the contract to a simpler fallback mode, which hopefully works when full mode doesn't.
    /// Not every contract needs to support fallback mode (FtsoManager does), so this method may be empty.
    /// Switching back to normal mode is left to the contract (typically a governed method call).
    /// This function may be called due to low-gas error, so it shouldn't use more than ~30.000 gas.
    /// @return true if switched to fallback mode, false if already in fallback mode or if falback not supported
    function switchToFallbackMode() external returns (bool);

    
    /// Implement this function for updating daemonized contracts through AddressUpdater.
    function getContractName() external view returns (string memory);
}
          

./contracts/genesis/interface/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/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/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/governance/implementation/Governed.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

import { GovernedBase } from "./GovernedBase.sol";


/**
 * @title Governed
 * @dev For deployed, governed contracts, enforce a non-zero address at create time.
 **/
contract Governed is GovernedBase {
    constructor(address _governance) GovernedBase(_governance) {
        require(_governance != address(0), "_governance zero");
    }
}
          

./contracts/governance/implementation/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/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/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/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/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/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/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/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);

}
          

./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/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);
}
          

./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;
}
          

@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);
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_addressUpdater","internalType":"address"}]},{"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":"TimelockedGovernanceCallCanceled","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallExecuted","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_ftsoIndex","internalType":"uint256"}],"name":"addFtso","inputs":[{"type":"address","name":"_ftsoContract","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoManager"}],"name":"ftsoManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_addressUpdater","internalType":"address"}],"name":"getAddressUpdater","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getAllFtsos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_price","internalType":"uint256"},{"type":"uint256","name":"_timestamp","internalType":"uint256"}],"name":"getCurrentPrice","inputs":[{"type":"string","name":"_symbol","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_price","internalType":"uint256"},{"type":"uint256","name":"_timestamp","internalType":"uint256"}],"name":"getCurrentPrice","inputs":[{"type":"uint256","name":"_assetIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_activeFtso","internalType":"contract IIFtso"}],"name":"getFtso","inputs":[{"type":"uint256","name":"_assetIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_activeFtso","internalType":"contract IIFtso"}],"name":"getFtsoBySymbol","inputs":[{"type":"string","name":"_symbol","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[5]","name":"_ftsoAddressHistory","internalType":"contract IIFtso[5]"}],"name":"getFtsoHistory","inputs":[{"type":"uint256","name":"_assetIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_assetIndex","internalType":"uint256"}],"name":"getFtsoIndex","inputs":[{"type":"string","name":"_symbol","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"_symbol","internalType":"string"}],"name":"getFtsoSymbol","inputs":[{"type":"uint256","name":"_assetIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IFtsoGenesis[]"}],"name":"getFtsos","inputs":[{"type":"uint256[]","name":"_assetIndices","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getSupportedFtsos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_supportedIndices","internalType":"uint256[]"}],"name":"getSupportedIndices","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_supportedIndices","internalType":"uint256[]"},{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getSupportedIndicesAndFtsos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_supportedIndices","internalType":"uint256[]"},{"type":"string[]","name":"_supportedSymbols","internalType":"string[]"}],"name":"getSupportedIndicesAndSymbols","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_supportedIndices","internalType":"uint256[]"},{"type":"string[]","name":"_supportedSymbols","internalType":"string[]"},{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getSupportedIndicesSymbolsAndFtsos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string[]","name":"_supportedSymbols","internalType":"string[]"}],"name":"getSupportedSymbols","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string[]","name":"_supportedSymbols","internalType":"string[]"},{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getSupportedSymbolsAndFtsos","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":"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":"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[]"}]}]
              

Contract Creation Code

0x60806040523480156200001157600080fd5b5060405162002c3138038062002c318339810160408190526200003491620001bb565b8082806001600160a01b0381161562000052576200005281620000b7565b506001600160a01b038116620000a2576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b50620000ae816200017a565b505050620001f2565b600054600160a01b900460ff161562000117576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b80516001600160a01b0381168114620001b657600080fd5b919050565b60008060408385031215620001ce578182fd5b620001d9836200019e565b9150620001e9602084016200019e565b90509250929050565b612a2f80620002026000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c8063798aac5b11610104578063c55d0f56116100a2578063e17f212e11610071578063e17f212e146103f0578063e68f283b14610405578063e848da301461041b578063f5a983831461042e576101cf565b8063c55d0f5614610395578063c71a1b20146103a8578063ce1c0e4d146103c8578063d75f6d81146103dd576101cf565b80639d6a890f116100de5780639d6a890f14610354578063a40060ba14610367578063a670ff871461036f578063b00c0b7614610382576101cf565b8063798aac5b1461030c57806397da6af4146103215780639cb4753814610334576101cf565b80635267a15d1161017157806362354e031161014b57806362354e03146102b957806367fc4029146102c157806374e6310e146102d45780637687542c146102f5576101cf565b80635267a15d146102945780635aa6e6751461029c5780635ff27079146102a4576101cf565b8063136d3f64116101ad578063136d3f641461021e5780632663f1b41461023e5780632bcdd6ab1461025e57806342a0f24314610273576101cf565b806306a2ba29146101d45780630cf48497146101f357806311a7aaaa14610209575b600080fd5b6101dc610436565b6040516101ea929190612866565b60405180910390f35b6101fb61050c565b6040516101ea92919061282e565b6102116106d1565b6040516101ea919061276d565b61023161022c366004612641565b6106e0565b6040516101ea91906128ec565b61025161024c3660046123d5565b610767565b6040516101ea91906128ff565b6102666109d4565b6040516101ea9190612808565b610286610281366004612565565b610a90565b6040516101ea929190612929565b610211610b1c565b610211610b41565b6102b76102b236600461253d565b610bd6565b005b610211610f2b565b6102b76102cf36600461253d565b610f36565b6102e76102e236600461253d565b61101e565b6040516101ea929190612908565b6102fd6110c4565b6040516101ea9392919061289e565b610314611289565b6040516101ea9190612853565b61021161032f366004612565565b611293565b6103476103423660046124ae565b6112a1565b6040516101ea9190612781565b6102b76103623660046123d5565b611425565b6102666114de565b6102b761037d3660046123d5565b6115b5565b6102b76103903660046123f8565b611829565b6102866103a3366004612641565b6118d4565b6103bb6103b6366004612641565b6118e0565b6040516101ea91906127ce565b6103d06119c6565b6040516101ea919061281b565b6102116103eb366004612641565b611afd565b6103f8611b08565b6040516101ea91906128e1565b61040d611b18565b6040516101ea929190612879565b610251610429366004612565565b611c4e565b6102b7611c59565b606080610441611d13565b8051909250806001600160401b038111801561045c57600080fd5b50604051908082528060200260200182016040528015610486578160200160208202803683370190505b5091505b8015610507578060019003905060028382815181106104a557fe5b6020026020010151815481106104b757fe5b600091825260208220600590910201015482516001600160a01b03909116908390839081106104e257fe5b60200260200101906001600160a01b031690816001600160a01b03168152505061048a565b509091565b6060806000610519611d13565b8051909150806001600160401b038111801561053457600080fd5b5060405190808252806020026020018201604052801561055e578160200160208202803683370190505b509250806001600160401b038111801561057757600080fd5b506040519080825280602002602001820160405280156105ab57816020015b60608152602001906001900390816105965790505b5093505b80156106cb578060019003905060028282815181106105ca57fe5b6020026020010151815481106105dc57fe5b600091825260208220600590910201015483516001600160a01b039091169084908390811061060757fe5b60200260200101906001600160a01b031690816001600160a01b03168152505082818151811061063357fe5b60200260200101516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561067357600080fd5b505afa158015610687573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106af91908101906125d8565b8482815181106106bb57fe5b60200260200101819052506105af565b50509091565b6003546001600160a01b031681565b60606106eb82611e54565b6001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561072357600080fd5b505afa158015610737573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261075f91908101906125d8565b90505b919050565b6003546040805180820190915260118152704654534f206d616e61676572206f6e6c7960781b60208201526000916001600160a01b031633146107c65760405162461bcd60e51b81526004016107bd91906128ec565b60405180910390fd5b50600060028054905090506000836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561080c57600080fd5b505afa158015610820573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261084891908101906125d8565b905060008160405160200161085d91906128ec565b604051602081830303815290604052805190602001209050600093505b8284101561096d5760006002858154811061089157fe5b60009182526020822060059091020101546001600160a01b03169050806108b85750610962565b806001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156108f157600080fd5b505afa158015610905573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261092d91908101906125d8565b60405160200161093d91906128ec565b60405160208183030381529060405280519060200120821415610960575061096d565b505b60019093019261087a565b828414156109865760028054600101815560005261098f565b61098f84611f0b565b846002858154811061099d57fe5b6000918252602082206005909102010180546001600160a01b0319166001600160a01b039290921691909117905550919392505050565b6002546060906000816001600160401b03811180156109f257600080fd5b50604051908082528060200260200182016040528015610a1c578160200160208202803683370190505b5090505b8115610a8a578160019003915060028281548110610a3a57fe5b600091825260208220600590910201015481516001600160a01b0390911690829084908110610a6557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050610a20565b91505090565b600080610aa4610a9f84611f9a565b611e54565b6001600160a01b031663eb91d37e6040518163ffffffff1660e01b8152600401604080518083038186803b158015610adb57600080fd5b505afa158015610aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b139190612659565b91509150915091565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff16610b64576000546001600160a01b0316610bd1565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b158015610ba457600080fd5b505afa158015610bb8573d6000803e3d6000fd5b505050506040513d6020811015610bce57600080fd5b50515b905090565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b158015610c1a57600080fd5b505afa158015610c2e573d6000803e3d6000fd5b505050506040513d6020811015610c4457600080fd5b5051610c87576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610cf3576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b8054421015610d49576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610de35780601f10610db857610100808354040283529160200191610de3565b820191906000526020600020905b815481529060010190602001808311610dc657829003601f168201915b5050506001600160e01b0319861660009081526001602081905260408220828155949550909250610e1791508301826122e5565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b60208310610e5f5780518252601f199092019160209182019101610e40565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610ec1576040519150601f19603f3d011682016040523d82523d6000602084013e610ec6565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a1610f25816120c4565b50505050565b60076001609c1b0181565b610f3e6120e1565b6001600160e01b03198116600090815260016020526040902054610fa9576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190611019908301826122e5565b505050565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156110ba5780601f1061108f576101008083540402835291602001916110ba565b820191906000526020600020905b81548152906001019060200180831161109d57829003601f168201915b5050505050905082565b60608060606110d1611d13565b8051909350806001600160401b03811180156110ec57600080fd5b50604051908082528060200260200182016040528015611116578160200160208202803683370190505b509150806001600160401b038111801561112f57600080fd5b5060405190808252806020026020018201604052801561116357816020015b606081526020019060019003908161114e5790505b5092505b80156112835780600190039050600284828151811061118257fe5b60200260200101518154811061119457fe5b600091825260208220600590910201015482516001600160a01b03909116908390839081106111bf57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508181815181106111eb57fe5b60200260200101516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561122b57600080fd5b505afa15801561123f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261126791908101906125d8565b83828151811061127357fe5b6020026020010181905250611167565b50909192565b6060610bd1611d13565b600061075f610a9f83611f9a565b600254815160609190806001600160401b03811180156112c057600080fd5b506040519080825280602002602001820160405280156112ea578160200160208202803683370190505b5092505b801561141e5780600190039050600084828151811061130957fe5b602002602001015190508281106040518060400160405280601881526020016000805160206129da833981519152815250906113585760405162461bcd60e51b81526004016107bd91906128ec565b506002818154811061136657fe5b600091825260208220600590910201015484516001600160a01b039091169085908490811061139157fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b03168483815181106113c857fe5b60200260200101516001600160a01b0316141561141857604080518082018252601881526000805160206129da8339815191526020820152905162461bcd60e51b81526107bd91906004016128ec565b506112ee565b5050919050565b600054600160a01b900460ff161561147b576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b606060006114ea611d13565b8051909150806001600160401b038111801561150557600080fd5b5060405190808252806020026020018201604052801561152f578160200160208202803683370190505b5092505b80156115b05780600190039050600282828151811061154e57fe5b60200260200101518154811061156057fe5b600091825260208220600590910201015483516001600160a01b039091169084908390811061158b57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611533565b505090565b6003546040805180820190915260118152704654534f206d616e61676572206f6e6c7960781b6020820152906001600160a01b031633146116095760405162461bcd60e51b81526004016107bd91906128ec565b506000816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561164557600080fd5b505afa158015611659573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261168191908101906125d8565b60405160200161169191906128ec565b60408051601f19818403018152919052805160209091012060025490915060005b818110156117ec576000600282815481106116c957fe5b60009182526020822060059091020101546001600160a01b03169050806116f057506117e4565b806001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561172957600080fd5b505afa15801561173d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261176591908101906125d8565b60405160200161177591906128ec565b604051602081830303815290604052805190602001208414156117e25761179b82611f0b565b6000600283815481106117aa57fe5b6000918252602082206005909102010180546001600160a01b0319166001600160a01b03929092169190911790555061182692505050565b505b6001016116b2565b50604080518082018252601881526000805160206129da8339815191526020820152905162461bcd60e51b81526107bd91906004016128ec565b50565b611831610b1c565b6001600160a01b0316336001600160a01b03161461188d576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b6118c66118c183836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250612142565b61226f565b6118d08282612293565b5050565b600080610aa483611e54565b6118e8612329565b60025482108015611929575060006001600160a01b03166002838154811061190c57fe5b60009182526020822060059091020101546001600160a01b031614155b6040518060400160405280601881526020016000805160206129da8339815191528152509061196b5760405162461bcd60e51b81526004016107bd91906128ec565b506002828154811061197957fe5b600091825260209091206040805160a0810191829052926005908102909201919082845b81546001600160a01b0316815260019091019060200180831161199d5750505050509050919050565b606060006119d2611d13565b8051909150806001600160401b03811180156119ed57600080fd5b50604051908082528060200260200182016040528015611a2157816020015b6060815260200190600190039081611a0c5790505b5092505b80156115b0578060019003905060006002838381518110611a4257fe5b602002602001015181548110611a5457fe5b6000918252602082206005919091020154604080516395d89b4160e01b815290516001600160a01b03909216935083926395d89b4192600480840193829003018186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ae091908101906125d8565b848381518110611aec57fe5b602002602001018190525050611a25565b600061075f82611e54565b600054600160a81b900460ff1681565b606080611b23611d13565b8051909250806001600160401b0381118015611b3e57600080fd5b50604051908082528060200260200182016040528015611b7257816020015b6060815260200190600190039081611b5d5790505b5091505b8015610507578060019003905060006002848381518110611b9357fe5b602002602001015181548110611ba557fe5b6000918252602082206005919091020154604080516395d89b4160e01b815290516001600160a01b03909216935083926395d89b4192600480840193829003018186803b158015611bf557600080fd5b505afa158015611c09573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c3191908101906125d8565b838381518110611c3d57fe5b602002602001018190525050611b76565b600061075f82611f9a565b611c616120e1565b600054600160a81b900460ff1615611cc0576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b6002546060906000816001600160401b0381118015611d3157600080fd5b50604051908082528060200260200182016040528015611d5b578160200160208202803683370190505b50905060008060005b84811015611dca57826001600160a01b031660028281548110611d8357fe5b60009182526020822060059091020101546001600160a01b031614611dc25780848381518110611daf57fe5b6020026020010181815250508160010191505b600101611d64565b50806001600160401b0381118015611de157600080fd5b50604051908082528060200260200182016040528015611e0b578160200160208202803683370190505b5094505b8015611e4d5780600190039050828181518110611e2857fe5b6020026020010151858281518110611e3c57fe5b602002602001018181525050611e0f565b5050505090565b60025460408051808201909152601881526000805160206129da83398151915260208201526000918310611e9b5760405162461bcd60e51b81526004016107bd91906128ec565b50600060028381548110611eab57fe5b60009182526020822060059091020101546001600160a01b0316905080611f0557604080518082018252601881526000805160206129da8339815191526020820152905162461bcd60e51b81526107bd91906004016128ec565b92915050565b60045b80156118d05760028281548110611f2157fe5b90600052602060002090600502016001820360058110611f3d57fe5b0154600280546001600160a01b039092169184908110611f5957fe5b90600052602060002090600502018260058110611f7257fe5b0180546001600160a01b0319166001600160a01b039290921691909117905560001901611f0e565b60008082604051602001611fae91906128ec565b60408051601f19818403018152919052805160209091012060025490915060005b818110156117ec57600060028281548110611fe657fe5b60009182526020822060059091020101546001600160a01b031690508061200d57506120bc565b806001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561204657600080fd5b505afa15801561205a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261208291908101906125d8565b60405160200161209291906128ec565b604051602081830303815290604052805190602001208414156120ba57509250610762915050565b505b600101611fcf565b3d604051818101604052816000823e82156120dd578181f35b8181fd5b6120e9610b41565b6001600160a01b0316336001600160a01b031614612140576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b8381101561218657818101518382015260200161216e565b50505050905090810190601f1680156121b35780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b865181101561221b578681815181106121e957fe5b60200260200101518314156122135785818151811061220457fe5b6020026020010151915061221b565b6001016121d4565b506001600160a01b038116612266576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b6122c182826040518060400160405280600b81526020016a233a39b7a6b0b730b3b2b960a91b815250612142565b600380546001600160a01b0319166001600160a01b03929092169190911790555050565b50805460018160011615610100020316600290046000825580601f1061230b5750611826565b601f0160209004906000526020600020908101906118269190612347565b6040518060a001604052806005906020820280368337509192915050565b5b8082111561235c5760008155600101612348565b5090565b600082601f830112612370578081fd5b813560206123856123808361295a565b612937565b82815281810190858301838502870184018810156123a1578586fd5b855b858110156123c85781356123b6816129c4565b845292840192908401906001016123a3565b5090979650505050505050565b6000602082840312156123e6578081fd5b81356123f1816129c4565b9392505050565b6000806040838503121561240a578081fd5b82356001600160401b0380821115612420578283fd5b818501915085601f830112612433578283fd5b813560206124436123808361295a565b82815281810190858301838502870184018b101561245f578788fd5b8796505b84871015612481578035835260019690960195918301918301612463565b5096505086013592505080821115612497578283fd5b506124a485828601612360565b9150509250929050565b600060208083850312156124c0578182fd5b82356001600160401b038111156124d5578283fd5b8301601f810185136124e5578283fd5b80356124f36123808261295a565b818152838101908385018584028501860189101561250f578687fd5b8694505b83851015612531578035835260019490940193918501918501612513565b50979650505050505050565b60006020828403121561254e578081fd5b81356001600160e01b0319811681146123f1578182fd5b600060208284031215612576578081fd5b81356001600160401b0381111561258b578182fd5b8201601f8101841361259b578182fd5b80356125a961238082612977565b8181528560208385010111156125bd578384fd5b81602084016020830137908101602001929092525092915050565b6000602082840312156125e9578081fd5b81516001600160401b038111156125fe578182fd5b8201601f8101841361260e578182fd5b805161261c61238082612977565b818152856020838501011115612630578384fd5b612266826020830160208601612998565b600060208284031215612652578081fd5b5035919050565b6000806040838503121561266b578182fd5b505080516020909101519092909150565b6000815180845260208085019450808401835b838110156126b45781516001600160a01b03168752958201959082019060010161268f565b509495945050505050565b6000815180845260208085018081965082840281019150828601855b858110156127055782840389526126f3848351612741565b988501989350908401906001016126db565b5091979650505050505050565b6000815180845260208085019450808401835b838110156126b457815187529582019590820190600101612725565b60008151808452612759816020860160208601612998565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b818110156127c25783516001600160a01b03168352928401929184019160010161279d565b50909695505050505050565b60a08101818360005b60058110156127ff5781516001600160a01b03168352602092830192909101906001016127d7565b50505092915050565b6000602082526123f1602083018461267c565b6000602082526123f160208301846126bf565b60006040825261284160408301856126bf565b8281036020840152612266818561267c565b6000602082526123f16020830184612712565b6000604082526128416040830185612712565b60006040825261288c6040830185612712565b828103602084015261226681856126bf565b6000606082526128b16060830186612712565b82810360208401526128c381866126bf565b905082810360408401526128d7818561267c565b9695505050505050565b901515815260200190565b6000602082526123f16020830184612741565b90815260200190565b6000838252604060208301526129216040830184612741565b949350505050565b918252602082015260400190565b6040518181016001600160401b038111828210171561295257fe5b604052919050565b60006001600160401b0382111561296d57fe5b5060209081020190565b60006001600160401b0382111561298a57fe5b50601f01601f191660200190565b60005b838110156129b357818101518382015260200161299b565b83811115610f255750506000910152565b6001600160a01b038116811461182657600080fdfe4654534f20696e646578206e6f7420737570706f727465640000000000000000a2646970667358221220143e5249452747d43dbff0b967f41811e80dbfba49bfbc3a7d910422514d4c0264736f6c634300070600330000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d29000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101cf5760003560e01c8063798aac5b11610104578063c55d0f56116100a2578063e17f212e11610071578063e17f212e146103f0578063e68f283b14610405578063e848da301461041b578063f5a983831461042e576101cf565b8063c55d0f5614610395578063c71a1b20146103a8578063ce1c0e4d146103c8578063d75f6d81146103dd576101cf565b80639d6a890f116100de5780639d6a890f14610354578063a40060ba14610367578063a670ff871461036f578063b00c0b7614610382576101cf565b8063798aac5b1461030c57806397da6af4146103215780639cb4753814610334576101cf565b80635267a15d1161017157806362354e031161014b57806362354e03146102b957806367fc4029146102c157806374e6310e146102d45780637687542c146102f5576101cf565b80635267a15d146102945780635aa6e6751461029c5780635ff27079146102a4576101cf565b8063136d3f64116101ad578063136d3f641461021e5780632663f1b41461023e5780632bcdd6ab1461025e57806342a0f24314610273576101cf565b806306a2ba29146101d45780630cf48497146101f357806311a7aaaa14610209575b600080fd5b6101dc610436565b6040516101ea929190612866565b60405180910390f35b6101fb61050c565b6040516101ea92919061282e565b6102116106d1565b6040516101ea919061276d565b61023161022c366004612641565b6106e0565b6040516101ea91906128ec565b61025161024c3660046123d5565b610767565b6040516101ea91906128ff565b6102666109d4565b6040516101ea9190612808565b610286610281366004612565565b610a90565b6040516101ea929190612929565b610211610b1c565b610211610b41565b6102b76102b236600461253d565b610bd6565b005b610211610f2b565b6102b76102cf36600461253d565b610f36565b6102e76102e236600461253d565b61101e565b6040516101ea929190612908565b6102fd6110c4565b6040516101ea9392919061289e565b610314611289565b6040516101ea9190612853565b61021161032f366004612565565b611293565b6103476103423660046124ae565b6112a1565b6040516101ea9190612781565b6102b76103623660046123d5565b611425565b6102666114de565b6102b761037d3660046123d5565b6115b5565b6102b76103903660046123f8565b611829565b6102866103a3366004612641565b6118d4565b6103bb6103b6366004612641565b6118e0565b6040516101ea91906127ce565b6103d06119c6565b6040516101ea919061281b565b6102116103eb366004612641565b611afd565b6103f8611b08565b6040516101ea91906128e1565b61040d611b18565b6040516101ea929190612879565b610251610429366004612565565b611c4e565b6102b7611c59565b606080610441611d13565b8051909250806001600160401b038111801561045c57600080fd5b50604051908082528060200260200182016040528015610486578160200160208202803683370190505b5091505b8015610507578060019003905060028382815181106104a557fe5b6020026020010151815481106104b757fe5b600091825260208220600590910201015482516001600160a01b03909116908390839081106104e257fe5b60200260200101906001600160a01b031690816001600160a01b03168152505061048a565b509091565b6060806000610519611d13565b8051909150806001600160401b038111801561053457600080fd5b5060405190808252806020026020018201604052801561055e578160200160208202803683370190505b509250806001600160401b038111801561057757600080fd5b506040519080825280602002602001820160405280156105ab57816020015b60608152602001906001900390816105965790505b5093505b80156106cb578060019003905060028282815181106105ca57fe5b6020026020010151815481106105dc57fe5b600091825260208220600590910201015483516001600160a01b039091169084908390811061060757fe5b60200260200101906001600160a01b031690816001600160a01b03168152505082818151811061063357fe5b60200260200101516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561067357600080fd5b505afa158015610687573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106af91908101906125d8565b8482815181106106bb57fe5b60200260200101819052506105af565b50509091565b6003546001600160a01b031681565b60606106eb82611e54565b6001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561072357600080fd5b505afa158015610737573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261075f91908101906125d8565b90505b919050565b6003546040805180820190915260118152704654534f206d616e61676572206f6e6c7960781b60208201526000916001600160a01b031633146107c65760405162461bcd60e51b81526004016107bd91906128ec565b60405180910390fd5b50600060028054905090506000836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561080c57600080fd5b505afa158015610820573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261084891908101906125d8565b905060008160405160200161085d91906128ec565b604051602081830303815290604052805190602001209050600093505b8284101561096d5760006002858154811061089157fe5b60009182526020822060059091020101546001600160a01b03169050806108b85750610962565b806001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156108f157600080fd5b505afa158015610905573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261092d91908101906125d8565b60405160200161093d91906128ec565b60405160208183030381529060405280519060200120821415610960575061096d565b505b60019093019261087a565b828414156109865760028054600101815560005261098f565b61098f84611f0b565b846002858154811061099d57fe5b6000918252602082206005909102010180546001600160a01b0319166001600160a01b039290921691909117905550919392505050565b6002546060906000816001600160401b03811180156109f257600080fd5b50604051908082528060200260200182016040528015610a1c578160200160208202803683370190505b5090505b8115610a8a578160019003915060028281548110610a3a57fe5b600091825260208220600590910201015481516001600160a01b0390911690829084908110610a6557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050610a20565b91505090565b600080610aa4610a9f84611f9a565b611e54565b6001600160a01b031663eb91d37e6040518163ffffffff1660e01b8152600401604080518083038186803b158015610adb57600080fd5b505afa158015610aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b139190612659565b91509150915091565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff16610b64576000546001600160a01b0316610bd1565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b158015610ba457600080fd5b505afa158015610bb8573d6000803e3d6000fd5b505050506040513d6020811015610bce57600080fd5b50515b905090565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b158015610c1a57600080fd5b505afa158015610c2e573d6000803e3d6000fd5b505050506040513d6020811015610c4457600080fd5b5051610c87576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610cf3576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b8054421015610d49576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610de35780601f10610db857610100808354040283529160200191610de3565b820191906000526020600020905b815481529060010190602001808311610dc657829003601f168201915b5050506001600160e01b0319861660009081526001602081905260408220828155949550909250610e1791508301826122e5565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b60208310610e5f5780518252601f199092019160209182019101610e40565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610ec1576040519150601f19603f3d011682016040523d82523d6000602084013e610ec6565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a1610f25816120c4565b50505050565b60076001609c1b0181565b610f3e6120e1565b6001600160e01b03198116600090815260016020526040902054610fa9576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190611019908301826122e5565b505050565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156110ba5780601f1061108f576101008083540402835291602001916110ba565b820191906000526020600020905b81548152906001019060200180831161109d57829003601f168201915b5050505050905082565b60608060606110d1611d13565b8051909350806001600160401b03811180156110ec57600080fd5b50604051908082528060200260200182016040528015611116578160200160208202803683370190505b509150806001600160401b038111801561112f57600080fd5b5060405190808252806020026020018201604052801561116357816020015b606081526020019060019003908161114e5790505b5092505b80156112835780600190039050600284828151811061118257fe5b60200260200101518154811061119457fe5b600091825260208220600590910201015482516001600160a01b03909116908390839081106111bf57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508181815181106111eb57fe5b60200260200101516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561122b57600080fd5b505afa15801561123f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261126791908101906125d8565b83828151811061127357fe5b6020026020010181905250611167565b50909192565b6060610bd1611d13565b600061075f610a9f83611f9a565b600254815160609190806001600160401b03811180156112c057600080fd5b506040519080825280602002602001820160405280156112ea578160200160208202803683370190505b5092505b801561141e5780600190039050600084828151811061130957fe5b602002602001015190508281106040518060400160405280601881526020016000805160206129da833981519152815250906113585760405162461bcd60e51b81526004016107bd91906128ec565b506002818154811061136657fe5b600091825260208220600590910201015484516001600160a01b039091169085908490811061139157fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b03168483815181106113c857fe5b60200260200101516001600160a01b0316141561141857604080518082018252601881526000805160206129da8339815191526020820152905162461bcd60e51b81526107bd91906004016128ec565b506112ee565b5050919050565b600054600160a01b900460ff161561147b576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b606060006114ea611d13565b8051909150806001600160401b038111801561150557600080fd5b5060405190808252806020026020018201604052801561152f578160200160208202803683370190505b5092505b80156115b05780600190039050600282828151811061154e57fe5b60200260200101518154811061156057fe5b600091825260208220600590910201015483516001600160a01b039091169084908390811061158b57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611533565b505090565b6003546040805180820190915260118152704654534f206d616e61676572206f6e6c7960781b6020820152906001600160a01b031633146116095760405162461bcd60e51b81526004016107bd91906128ec565b506000816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561164557600080fd5b505afa158015611659573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261168191908101906125d8565b60405160200161169191906128ec565b60408051601f19818403018152919052805160209091012060025490915060005b818110156117ec576000600282815481106116c957fe5b60009182526020822060059091020101546001600160a01b03169050806116f057506117e4565b806001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561172957600080fd5b505afa15801561173d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261176591908101906125d8565b60405160200161177591906128ec565b604051602081830303815290604052805190602001208414156117e25761179b82611f0b565b6000600283815481106117aa57fe5b6000918252602082206005909102010180546001600160a01b0319166001600160a01b03929092169190911790555061182692505050565b505b6001016116b2565b50604080518082018252601881526000805160206129da8339815191526020820152905162461bcd60e51b81526107bd91906004016128ec565b50565b611831610b1c565b6001600160a01b0316336001600160a01b03161461188d576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b6118c66118c183836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250612142565b61226f565b6118d08282612293565b5050565b600080610aa483611e54565b6118e8612329565b60025482108015611929575060006001600160a01b03166002838154811061190c57fe5b60009182526020822060059091020101546001600160a01b031614155b6040518060400160405280601881526020016000805160206129da8339815191528152509061196b5760405162461bcd60e51b81526004016107bd91906128ec565b506002828154811061197957fe5b600091825260209091206040805160a0810191829052926005908102909201919082845b81546001600160a01b0316815260019091019060200180831161199d5750505050509050919050565b606060006119d2611d13565b8051909150806001600160401b03811180156119ed57600080fd5b50604051908082528060200260200182016040528015611a2157816020015b6060815260200190600190039081611a0c5790505b5092505b80156115b0578060019003905060006002838381518110611a4257fe5b602002602001015181548110611a5457fe5b6000918252602082206005919091020154604080516395d89b4160e01b815290516001600160a01b03909216935083926395d89b4192600480840193829003018186803b158015611aa457600080fd5b505afa158015611ab8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ae091908101906125d8565b848381518110611aec57fe5b602002602001018190525050611a25565b600061075f82611e54565b600054600160a81b900460ff1681565b606080611b23611d13565b8051909250806001600160401b0381118015611b3e57600080fd5b50604051908082528060200260200182016040528015611b7257816020015b6060815260200190600190039081611b5d5790505b5091505b8015610507578060019003905060006002848381518110611b9357fe5b602002602001015181548110611ba557fe5b6000918252602082206005919091020154604080516395d89b4160e01b815290516001600160a01b03909216935083926395d89b4192600480840193829003018186803b158015611bf557600080fd5b505afa158015611c09573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c3191908101906125d8565b838381518110611c3d57fe5b602002602001018190525050611b76565b600061075f82611f9a565b611c616120e1565b600054600160a81b900460ff1615611cc0576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b6002546060906000816001600160401b0381118015611d3157600080fd5b50604051908082528060200260200182016040528015611d5b578160200160208202803683370190505b50905060008060005b84811015611dca57826001600160a01b031660028281548110611d8357fe5b60009182526020822060059091020101546001600160a01b031614611dc25780848381518110611daf57fe5b6020026020010181815250508160010191505b600101611d64565b50806001600160401b0381118015611de157600080fd5b50604051908082528060200260200182016040528015611e0b578160200160208202803683370190505b5094505b8015611e4d5780600190039050828181518110611e2857fe5b6020026020010151858281518110611e3c57fe5b602002602001018181525050611e0f565b5050505090565b60025460408051808201909152601881526000805160206129da83398151915260208201526000918310611e9b5760405162461bcd60e51b81526004016107bd91906128ec565b50600060028381548110611eab57fe5b60009182526020822060059091020101546001600160a01b0316905080611f0557604080518082018252601881526000805160206129da8339815191526020820152905162461bcd60e51b81526107bd91906004016128ec565b92915050565b60045b80156118d05760028281548110611f2157fe5b90600052602060002090600502016001820360058110611f3d57fe5b0154600280546001600160a01b039092169184908110611f5957fe5b90600052602060002090600502018260058110611f7257fe5b0180546001600160a01b0319166001600160a01b039290921691909117905560001901611f0e565b60008082604051602001611fae91906128ec565b60408051601f19818403018152919052805160209091012060025490915060005b818110156117ec57600060028281548110611fe657fe5b60009182526020822060059091020101546001600160a01b031690508061200d57506120bc565b806001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561204657600080fd5b505afa15801561205a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261208291908101906125d8565b60405160200161209291906128ec565b604051602081830303815290604052805190602001208414156120ba57509250610762915050565b505b600101611fcf565b3d604051818101604052816000823e82156120dd578181f35b8181fd5b6120e9610b41565b6001600160a01b0316336001600160a01b031614612140576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b8381101561218657818101518382015260200161216e565b50505050905090810190601f1680156121b35780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b865181101561221b578681815181106121e957fe5b60200260200101518314156122135785818151811061220457fe5b6020026020010151915061221b565b6001016121d4565b506001600160a01b038116612266576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b6122c182826040518060400160405280600b81526020016a233a39b7a6b0b730b3b2b960a91b815250612142565b600380546001600160a01b0319166001600160a01b03929092169190911790555050565b50805460018160011615610100020316600290046000825580601f1061230b5750611826565b601f0160209004906000526020600020908101906118269190612347565b6040518060a001604052806005906020820280368337509192915050565b5b8082111561235c5760008155600101612348565b5090565b600082601f830112612370578081fd5b813560206123856123808361295a565b612937565b82815281810190858301838502870184018810156123a1578586fd5b855b858110156123c85781356123b6816129c4565b845292840192908401906001016123a3565b5090979650505050505050565b6000602082840312156123e6578081fd5b81356123f1816129c4565b9392505050565b6000806040838503121561240a578081fd5b82356001600160401b0380821115612420578283fd5b818501915085601f830112612433578283fd5b813560206124436123808361295a565b82815281810190858301838502870184018b101561245f578788fd5b8796505b84871015612481578035835260019690960195918301918301612463565b5096505086013592505080821115612497578283fd5b506124a485828601612360565b9150509250929050565b600060208083850312156124c0578182fd5b82356001600160401b038111156124d5578283fd5b8301601f810185136124e5578283fd5b80356124f36123808261295a565b818152838101908385018584028501860189101561250f578687fd5b8694505b83851015612531578035835260019490940193918501918501612513565b50979650505050505050565b60006020828403121561254e578081fd5b81356001600160e01b0319811681146123f1578182fd5b600060208284031215612576578081fd5b81356001600160401b0381111561258b578182fd5b8201601f8101841361259b578182fd5b80356125a961238082612977565b8181528560208385010111156125bd578384fd5b81602084016020830137908101602001929092525092915050565b6000602082840312156125e9578081fd5b81516001600160401b038111156125fe578182fd5b8201601f8101841361260e578182fd5b805161261c61238082612977565b818152856020838501011115612630578384fd5b612266826020830160208601612998565b600060208284031215612652578081fd5b5035919050565b6000806040838503121561266b578182fd5b505080516020909101519092909150565b6000815180845260208085019450808401835b838110156126b45781516001600160a01b03168752958201959082019060010161268f565b509495945050505050565b6000815180845260208085018081965082840281019150828601855b858110156127055782840389526126f3848351612741565b988501989350908401906001016126db565b5091979650505050505050565b6000815180845260208085019450808401835b838110156126b457815187529582019590820190600101612725565b60008151808452612759816020860160208601612998565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b818110156127c25783516001600160a01b03168352928401929184019160010161279d565b50909695505050505050565b60a08101818360005b60058110156127ff5781516001600160a01b03168352602092830192909101906001016127d7565b50505092915050565b6000602082526123f1602083018461267c565b6000602082526123f160208301846126bf565b60006040825261284160408301856126bf565b8281036020840152612266818561267c565b6000602082526123f16020830184612712565b6000604082526128416040830185612712565b60006040825261288c6040830185612712565b828103602084015261226681856126bf565b6000606082526128b16060830186612712565b82810360208401526128c381866126bf565b905082810360408401526128d7818561267c565b9695505050505050565b901515815260200190565b6000602082526123f16020830184612741565b90815260200190565b6000838252604060208301526129216040830184612741565b949350505050565b918252602082015260400190565b6040518181016001600160401b038111828210171561295257fe5b604052919050565b60006001600160401b0382111561296d57fe5b5060209081020190565b60006001600160401b0382111561298a57fe5b50601f01601f191660200190565b60005b838110156129b357818101518382015260200161299b565b83811115610f255750506000910152565b6001600160a01b038116811461182657600080fdfe4654534f20696e646578206e6f7420737570706f727465640000000000000000a2646970667358221220143e5249452747d43dbff0b967f41811e80dbfba49bfbc3a7d910422514d4c0264736f6c63430007060033