OP Sepolia Testnet

Contract

0x46D3a0308b70a221AE65865d62308197D4c95400

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FeePool

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 1500 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at sepolia-optimism.etherscan.io on 2023-12-11
*/

/*

⚠⚠⚠ WARNING WARNING WARNING ⚠⚠⚠

This is a TARGET contract - DO NOT CONNECT TO IT DIRECTLY IN YOUR CONTRACTS or DAPPS!

This contract has an associated PROXY that MUST be used for all integrations - this TARGET will be REPLACED in an upcoming Synthetix release!
The proxy for this contract can be found here:

https://contracts.synthetix.io/sepolia//ovmProxyFeePool

*//*
   ____            __   __        __   _
  / __/__ __ ___  / /_ / /  ___  / /_ (_)__ __
 _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ /
/___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\
     /___/

* Synthetix: FeePool.sol
*
* Latest source (may be newer): https://github.com/Synthetixio/synthetix/blob/master/contracts/FeePool.sol
* Docs: https://docs.synthetix.io/contracts/FeePool
*
* Contract Dependencies: 
*	- EternalStorage
*	- IAddressResolver
*	- IFeePool
*	- LimitedSetup
*	- MixinResolver
*	- MixinSystemSettings
*	- Owned
*	- Proxyable
*	- State
* Libraries: 
*	- SafeDecimalMath
*	- SafeMath
*	- VestingEntries
*
* MIT License
* ===========
*
* Copyright (c) 2023 Synthetix
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/



pragma solidity ^0.5.16;

// https://docs.synthetix.io/contracts/source/contracts/owned
contract Owned {
    address public owner;
    address public nominatedOwner;

    constructor(address _owner) public {
        require(_owner != address(0), "Owner address cannot be 0");
        owner = _owner;
        emit OwnerChanged(address(0), _owner);
    }

    function nominateNewOwner(address _owner) external onlyOwner {
        nominatedOwner = _owner;
        emit OwnerNominated(_owner);
    }

    function acceptOwnership() external {
        require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
        emit OwnerChanged(owner, nominatedOwner);
        owner = nominatedOwner;
        nominatedOwner = address(0);
    }

    modifier onlyOwner {
        _onlyOwner();
        _;
    }

    function _onlyOwner() private view {
        require(msg.sender == owner, "Only the contract owner may perform this action");
    }

    event OwnerNominated(address newOwner);
    event OwnerChanged(address oldOwner, address newOwner);
}


// Inheritance


// Internal references


// https://docs.synthetix.io/contracts/source/contracts/proxy
contract Proxy is Owned {
    Proxyable public target;

    constructor(address _owner) public Owned(_owner) {}

    function setTarget(Proxyable _target) external onlyOwner {
        target = _target;
        emit TargetUpdated(_target);
    }

    function _emit(
        bytes calldata callData,
        uint numTopics,
        bytes32 topic1,
        bytes32 topic2,
        bytes32 topic3,
        bytes32 topic4
    ) external onlyTarget {
        uint size = callData.length;
        bytes memory _callData = callData;

        assembly {
            /* The first 32 bytes of callData contain its length (as specified by the abi).
             * Length is assumed to be a uint256 and therefore maximum of 32 bytes
             * in length. It is also leftpadded to be a multiple of 32 bytes.
             * This means moving call_data across 32 bytes guarantees we correctly access
             * the data itself. */
            switch numTopics
                case 0 {
                    log0(add(_callData, 32), size)
                }
                case 1 {
                    log1(add(_callData, 32), size, topic1)
                }
                case 2 {
                    log2(add(_callData, 32), size, topic1, topic2)
                }
                case 3 {
                    log3(add(_callData, 32), size, topic1, topic2, topic3)
                }
                case 4 {
                    log4(add(_callData, 32), size, topic1, topic2, topic3, topic4)
                }
        }
    }

    // solhint-disable no-complex-fallback
    function() external payable {
        // Mutable call setting Proxyable.messageSender as this is using call not delegatecall
        target.setMessageSender(msg.sender);

        assembly {
            let free_ptr := mload(0x40)
            calldatacopy(free_ptr, 0, calldatasize)

            /* We must explicitly forward ether to the underlying contract as well. */
            let result := call(gas, sload(target_slot), callvalue, free_ptr, calldatasize, 0, 0)
            returndatacopy(free_ptr, 0, returndatasize)

            if iszero(result) {
                revert(free_ptr, returndatasize)
            }
            return(free_ptr, returndatasize)
        }
    }

    modifier onlyTarget {
        require(Proxyable(msg.sender) == target, "Must be proxy target");
        _;
    }

    event TargetUpdated(Proxyable newTarget);
}


// Inheritance


// Internal references


// https://docs.synthetix.io/contracts/source/contracts/proxyable
contract Proxyable is Owned {
    // This contract should be treated like an abstract contract

    /* The proxy this contract exists behind. */
    Proxy public proxy;

    /* The caller of the proxy, passed through to this contract.
     * Note that every function using this member must apply the onlyProxy or
     * optionalProxy modifiers, otherwise their invocations can use stale values. */
    address public messageSender;

    constructor(address payable _proxy) internal {
        // This contract is abstract, and thus cannot be instantiated directly
        require(owner != address(0), "Owner must be set");

        proxy = Proxy(_proxy);
        emit ProxyUpdated(_proxy);
    }

    function setProxy(address payable _proxy) external onlyOwner {
        proxy = Proxy(_proxy);
        emit ProxyUpdated(_proxy);
    }

    function setMessageSender(address sender) external onlyProxy {
        messageSender = sender;
    }

    modifier onlyProxy {
        _onlyProxy();
        _;
    }

    function _onlyProxy() private view {
        require(Proxy(msg.sender) == proxy, "Only the proxy can call");
    }

    modifier optionalProxy {
        _optionalProxy();
        _;
    }

    function _optionalProxy() private {
        if (Proxy(msg.sender) != proxy && messageSender != msg.sender) {
            messageSender = msg.sender;
        }
    }

    modifier optionalProxy_onlyOwner {
        _optionalProxy_onlyOwner();
        _;
    }

    // solhint-disable-next-line func-name-mixedcase
    function _optionalProxy_onlyOwner() private {
        if (Proxy(msg.sender) != proxy && messageSender != msg.sender) {
            messageSender = msg.sender;
        }
        require(messageSender == owner, "Owner only function");
    }

    event ProxyUpdated(address proxyAddress);
}


// https://docs.synthetix.io/contracts/source/contracts/limitedsetup
contract LimitedSetup {
    uint public setupExpiryTime;

    /**
     * @dev LimitedSetup Constructor.
     * @param setupDuration The time the setup period will last for.
     */
    constructor(uint setupDuration) internal {
        setupExpiryTime = now + setupDuration;
    }

    modifier onlyDuringSetup {
        require(now < setupExpiryTime, "Can only perform this action during setup");
        _;
    }
}


// https://docs.synthetix.io/contracts/source/interfaces/iaddressresolver
interface IAddressResolver {
    function getAddress(bytes32 name) external view returns (address);

    function getSynth(bytes32 key) external view returns (address);

    function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address);
}


// https://docs.synthetix.io/contracts/source/interfaces/isynth
interface ISynth {
    // Views
    function currencyKey() external view returns (bytes32);

    function transferableSynths(address account) external view returns (uint);

    // Mutative functions
    function transferAndSettle(address to, uint value) external returns (bool);

    function transferFromAndSettle(
        address from,
        address to,
        uint value
    ) external returns (bool);

    // Restricted: used internally to Synthetix
    function burn(address account, uint amount) external;

    function issue(address account, uint amount) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/iissuer
interface IIssuer {
    // Views

    function allNetworksDebtInfo()
        external
        view
        returns (
            uint256 debt,
            uint256 sharesSupply,
            bool isStale
        );

    function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid);

    function availableCurrencyKeys() external view returns (bytes32[] memory);

    function availableSynthCount() external view returns (uint);

    function availableSynths(uint index) external view returns (ISynth);

    function canBurnSynths(address account) external view returns (bool);

    function collateral(address account) external view returns (uint);

    function collateralisationRatio(address issuer) external view returns (uint);

    function collateralisationRatioAndAnyRatesInvalid(address _issuer)
        external
        view
        returns (uint cratio, bool anyRateIsInvalid);

    function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint debtBalance);

    function issuanceRatio() external view returns (uint);

    function lastIssueEvent(address account) external view returns (uint);

    function maxIssuableSynths(address issuer) external view returns (uint maxIssuable);

    function minimumStakeTime() external view returns (uint);

    function remainingIssuableSynths(address issuer)
        external
        view
        returns (
            uint maxIssuable,
            uint alreadyIssued,
            uint totalSystemDebt
        );

    function synths(bytes32 currencyKey) external view returns (ISynth);

    function getSynths(bytes32[] calldata currencyKeys) external view returns (ISynth[] memory);

    function synthsByAddress(address synthAddress) external view returns (bytes32);

    function totalIssuedSynths(bytes32 currencyKey, bool excludeOtherCollateral) external view returns (uint);

    function transferableSynthetixAndAnyRateIsInvalid(address account, uint balance)
        external
        view
        returns (uint transferable, bool anyRateIsInvalid);

    function liquidationAmounts(address account, bool isSelfLiquidation)
        external
        view
        returns (
            uint totalRedeemed,
            uint debtToRemove,
            uint escrowToLiquidate,
            uint initialDebtBalance
        );

    // Restricted: used internally to Synthetix
    function addSynths(ISynth[] calldata synthsToAdd) external;

    function issueSynths(address from, uint amount) external;

    function issueSynthsOnBehalf(
        address issueFor,
        address from,
        uint amount
    ) external;

    function issueMaxSynths(address from) external;

    function issueMaxSynthsOnBehalf(address issueFor, address from) external;

    function burnSynths(address from, uint amount) external;

    function burnSynthsOnBehalf(
        address burnForAddress,
        address from,
        uint amount
    ) external;

    function burnSynthsToTarget(address from) external;

    function burnSynthsToTargetOnBehalf(address burnForAddress, address from) external;

    function burnForRedemption(
        address deprecatedSynthProxy,
        address account,
        uint balance
    ) external;

    function setCurrentPeriodId(uint128 periodId) external;

    function liquidateAccount(address account, bool isSelfLiquidation)
        external
        returns (
            uint totalRedeemed,
            uint debtRemoved,
            uint escrowToLiquidate
        );

    function issueSynthsWithoutDebt(
        bytes32 currencyKey,
        address to,
        uint amount
    ) external returns (bool rateInvalid);

    function burnSynthsWithoutDebt(
        bytes32 currencyKey,
        address to,
        uint amount
    ) external returns (bool rateInvalid);

    function modifyDebtSharesForMigration(address account, uint amount) external;
}


// Inheritance


// Internal references


// https://docs.synthetix.io/contracts/source/contracts/addressresolver
contract AddressResolver is Owned, IAddressResolver {
    mapping(bytes32 => address) public repository;

    constructor(address _owner) public Owned(_owner) {}

    /* ========== RESTRICTED FUNCTIONS ========== */

    function importAddresses(bytes32[] calldata names, address[] calldata destinations) external onlyOwner {
        require(names.length == destinations.length, "Input lengths must match");

        for (uint i = 0; i < names.length; i++) {
            bytes32 name = names[i];
            address destination = destinations[i];
            repository[name] = destination;
            emit AddressImported(name, destination);
        }
    }

    /* ========= PUBLIC FUNCTIONS ========== */

    function rebuildCaches(MixinResolver[] calldata destinations) external {
        for (uint i = 0; i < destinations.length; i++) {
            destinations[i].rebuildCache();
        }
    }

    /* ========== VIEWS ========== */

    function areAddressesImported(bytes32[] calldata names, address[] calldata destinations) external view returns (bool) {
        for (uint i = 0; i < names.length; i++) {
            if (repository[names[i]] != destinations[i]) {
                return false;
            }
        }
        return true;
    }

    function getAddress(bytes32 name) external view returns (address) {
        return repository[name];
    }

    function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address) {
        address _foundAddress = repository[name];
        require(_foundAddress != address(0), reason);
        return _foundAddress;
    }

    function getSynth(bytes32 key) external view returns (address) {
        IIssuer issuer = IIssuer(repository["Issuer"]);
        require(address(issuer) != address(0), "Cannot find Issuer address");
        return address(issuer.synths(key));
    }

    /* ========== EVENTS ========== */

    event AddressImported(bytes32 name, address destination);
}


// Internal references


// https://docs.synthetix.io/contracts/source/contracts/mixinresolver
contract MixinResolver {
    AddressResolver public resolver;

    mapping(bytes32 => address) private addressCache;

    constructor(address _resolver) internal {
        resolver = AddressResolver(_resolver);
    }

    /* ========== INTERNAL FUNCTIONS ========== */

    function combineArrays(bytes32[] memory first, bytes32[] memory second)
        internal
        pure
        returns (bytes32[] memory combination)
    {
        combination = new bytes32[](first.length + second.length);

        for (uint i = 0; i < first.length; i++) {
            combination[i] = first[i];
        }

        for (uint j = 0; j < second.length; j++) {
            combination[first.length + j] = second[j];
        }
    }

    /* ========== PUBLIC FUNCTIONS ========== */

    // Note: this function is public not external in order for it to be overridden and invoked via super in subclasses
    function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {}

    function rebuildCache() public {
        bytes32[] memory requiredAddresses = resolverAddressesRequired();
        // The resolver must call this function whenver it updates its state
        for (uint i = 0; i < requiredAddresses.length; i++) {
            bytes32 name = requiredAddresses[i];
            // Note: can only be invoked once the resolver has all the targets needed added
            address destination =
                resolver.requireAndGetAddress(name, string(abi.encodePacked("Resolver missing target: ", name)));
            addressCache[name] = destination;
            emit CacheUpdated(name, destination);
        }
    }

    /* ========== VIEWS ========== */

    function isResolverCached() external view returns (bool) {
        bytes32[] memory requiredAddresses = resolverAddressesRequired();
        for (uint i = 0; i < requiredAddresses.length; i++) {
            bytes32 name = requiredAddresses[i];
            // false if our cache is invalid or if the resolver doesn't have the required address
            if (resolver.getAddress(name) != addressCache[name] || addressCache[name] == address(0)) {
                return false;
            }
        }

        return true;
    }

    /* ========== INTERNAL FUNCTIONS ========== */

    function requireAndGetAddress(bytes32 name) internal view returns (address) {
        address _foundAddress = addressCache[name];
        require(_foundAddress != address(0), string(abi.encodePacked("Missing address: ", name)));
        return _foundAddress;
    }

    /* ========== EVENTS ========== */

    event CacheUpdated(bytes32 name, address destination);
}


// https://docs.synthetix.io/contracts/source/interfaces/iflexiblestorage
interface IFlexibleStorage {
    // Views
    function getUIntValue(bytes32 contractName, bytes32 record) external view returns (uint);

    function getUIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (uint[] memory);

    function getIntValue(bytes32 contractName, bytes32 record) external view returns (int);

    function getIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (int[] memory);

    function getAddressValue(bytes32 contractName, bytes32 record) external view returns (address);

    function getAddressValues(bytes32 contractName, bytes32[] calldata records) external view returns (address[] memory);

    function getBoolValue(bytes32 contractName, bytes32 record) external view returns (bool);

    function getBoolValues(bytes32 contractName, bytes32[] calldata records) external view returns (bool[] memory);

    function getBytes32Value(bytes32 contractName, bytes32 record) external view returns (bytes32);

    function getBytes32Values(bytes32 contractName, bytes32[] calldata records) external view returns (bytes32[] memory);

    // Mutative functions
    function deleteUIntValue(bytes32 contractName, bytes32 record) external;

    function deleteIntValue(bytes32 contractName, bytes32 record) external;

    function deleteAddressValue(bytes32 contractName, bytes32 record) external;

    function deleteBoolValue(bytes32 contractName, bytes32 record) external;

    function deleteBytes32Value(bytes32 contractName, bytes32 record) external;

    function setUIntValue(
        bytes32 contractName,
        bytes32 record,
        uint value
    ) external;

    function setUIntValues(
        bytes32 contractName,
        bytes32[] calldata records,
        uint[] calldata values
    ) external;

    function setIntValue(
        bytes32 contractName,
        bytes32 record,
        int value
    ) external;

    function setIntValues(
        bytes32 contractName,
        bytes32[] calldata records,
        int[] calldata values
    ) external;

    function setAddressValue(
        bytes32 contractName,
        bytes32 record,
        address value
    ) external;

    function setAddressValues(
        bytes32 contractName,
        bytes32[] calldata records,
        address[] calldata values
    ) external;

    function setBoolValue(
        bytes32 contractName,
        bytes32 record,
        bool value
    ) external;

    function setBoolValues(
        bytes32 contractName,
        bytes32[] calldata records,
        bool[] calldata values
    ) external;

    function setBytes32Value(
        bytes32 contractName,
        bytes32 record,
        bytes32 value
    ) external;

    function setBytes32Values(
        bytes32 contractName,
        bytes32[] calldata records,
        bytes32[] calldata values
    ) external;
}


// Internal references


// https://docs.synthetix.io/contracts/source/contracts/mixinsystemsettings
contract MixinSystemSettings is MixinResolver {
    // must match the one defined SystemSettingsLib, defined in both places due to sol v0.5 limitations
    bytes32 internal constant SETTING_CONTRACT_NAME = "SystemSettings";

    bytes32 internal constant SETTING_WAITING_PERIOD_SECS = "waitingPeriodSecs";
    bytes32 internal constant SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR = "priceDeviationThresholdFactor";
    bytes32 internal constant SETTING_ISSUANCE_RATIO = "issuanceRatio";
    bytes32 internal constant SETTING_FEE_PERIOD_DURATION = "feePeriodDuration";
    bytes32 internal constant SETTING_TARGET_THRESHOLD = "targetThreshold";
    bytes32 internal constant SETTING_LIQUIDATION_DELAY = "liquidationDelay";
    bytes32 internal constant SETTING_LIQUIDATION_RATIO = "liquidationRatio";
    bytes32 internal constant SETTING_LIQUIDATION_ESCROW_DURATION = "liquidationEscrowDuration";
    bytes32 internal constant SETTING_LIQUIDATION_PENALTY = "liquidationPenalty";
    bytes32 internal constant SETTING_SNX_LIQUIDATION_PENALTY = "snxLiquidationPenalty";
    bytes32 internal constant SETTING_SELF_LIQUIDATION_PENALTY = "selfLiquidationPenalty";
    bytes32 internal constant SETTING_FLAG_REWARD = "flagReward";
    bytes32 internal constant SETTING_LIQUIDATE_REWARD = "liquidateReward";
    bytes32 internal constant SETTING_RATE_STALE_PERIOD = "rateStalePeriod";
    /* ========== Exchange Fees Related ========== */
    bytes32 internal constant SETTING_EXCHANGE_FEE_RATE = "exchangeFeeRate";
    bytes32 internal constant SETTING_EXCHANGE_DYNAMIC_FEE_THRESHOLD = "exchangeDynamicFeeThreshold";
    bytes32 internal constant SETTING_EXCHANGE_DYNAMIC_FEE_WEIGHT_DECAY = "exchangeDynamicFeeWeightDecay";
    bytes32 internal constant SETTING_EXCHANGE_DYNAMIC_FEE_ROUNDS = "exchangeDynamicFeeRounds";
    bytes32 internal constant SETTING_EXCHANGE_MAX_DYNAMIC_FEE = "exchangeMaxDynamicFee";
    /* ========== End Exchange Fees Related ========== */
    bytes32 internal constant SETTING_MINIMUM_STAKE_TIME = "minimumStakeTime";
    bytes32 internal constant SETTING_AGGREGATOR_WARNING_FLAGS = "aggregatorWarningFlags";
    bytes32 internal constant SETTING_TRADING_REWARDS_ENABLED = "tradingRewardsEnabled";
    bytes32 internal constant SETTING_DEBT_SNAPSHOT_STALE_TIME = "debtSnapshotStaleTime";
    bytes32 internal constant SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT = "crossDomainDepositGasLimit";
    bytes32 internal constant SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT = "crossDomainEscrowGasLimit";
    bytes32 internal constant SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT = "crossDomainRewardGasLimit";
    bytes32 internal constant SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT = "crossDomainWithdrawalGasLimit";
    bytes32 internal constant SETTING_CROSS_DOMAIN_FEE_PERIOD_CLOSE_GAS_LIMIT = "crossDomainCloseGasLimit";
    bytes32 internal constant SETTING_CROSS_DOMAIN_RELAY_GAS_LIMIT = "crossDomainRelayGasLimit";
    bytes32 internal constant SETTING_ETHER_WRAPPER_MAX_ETH = "etherWrapperMaxETH";
    bytes32 internal constant SETTING_ETHER_WRAPPER_MINT_FEE_RATE = "etherWrapperMintFeeRate";
    bytes32 internal constant SETTING_ETHER_WRAPPER_BURN_FEE_RATE = "etherWrapperBurnFeeRate";
    bytes32 internal constant SETTING_WRAPPER_MAX_TOKEN_AMOUNT = "wrapperMaxTokens";
    bytes32 internal constant SETTING_WRAPPER_MINT_FEE_RATE = "wrapperMintFeeRate";
    bytes32 internal constant SETTING_WRAPPER_BURN_FEE_RATE = "wrapperBurnFeeRate";
    bytes32 internal constant SETTING_INTERACTION_DELAY = "interactionDelay";
    bytes32 internal constant SETTING_COLLAPSE_FEE_RATE = "collapseFeeRate";
    bytes32 internal constant SETTING_ATOMIC_MAX_VOLUME_PER_BLOCK = "atomicMaxVolumePerBlock";
    bytes32 internal constant SETTING_ATOMIC_TWAP_WINDOW = "atomicTwapWindow";
    bytes32 internal constant SETTING_ATOMIC_EQUIVALENT_FOR_DEX_PRICING = "atomicEquivalentForDexPricing";
    bytes32 internal constant SETTING_ATOMIC_EXCHANGE_FEE_RATE = "atomicExchangeFeeRate";
    bytes32 internal constant SETTING_ATOMIC_VOLATILITY_CONSIDERATION_WINDOW = "atomicVolConsiderationWindow";
    bytes32 internal constant SETTING_ATOMIC_VOLATILITY_UPDATE_THRESHOLD = "atomicVolUpdateThreshold";
    bytes32 internal constant SETTING_PURE_CHAINLINK_PRICE_FOR_ATOMIC_SWAPS_ENABLED = "pureChainlinkForAtomicsEnabled";
    bytes32 internal constant SETTING_CROSS_SYNTH_TRANSFER_ENABLED = "crossChainSynthTransferEnabled";

    bytes32 internal constant CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage";

    enum CrossDomainMessageGasLimits {Deposit, Escrow, Reward, Withdrawal, CloseFeePeriod, Relay}

    struct DynamicFeeConfig {
        uint threshold;
        uint weightDecay;
        uint rounds;
        uint maxFee;
    }

    constructor(address _resolver) internal MixinResolver(_resolver) {}

    function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
        addresses = new bytes32[](1);
        addresses[0] = CONTRACT_FLEXIBLESTORAGE;
    }

    function flexibleStorage() internal view returns (IFlexibleStorage) {
        return IFlexibleStorage(requireAndGetAddress(CONTRACT_FLEXIBLESTORAGE));
    }

    function _getGasLimitSetting(CrossDomainMessageGasLimits gasLimitType) internal pure returns (bytes32) {
        if (gasLimitType == CrossDomainMessageGasLimits.Deposit) {
            return SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT;
        } else if (gasLimitType == CrossDomainMessageGasLimits.Escrow) {
            return SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT;
        } else if (gasLimitType == CrossDomainMessageGasLimits.Reward) {
            return SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT;
        } else if (gasLimitType == CrossDomainMessageGasLimits.Withdrawal) {
            return SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT;
        } else if (gasLimitType == CrossDomainMessageGasLimits.Relay) {
            return SETTING_CROSS_DOMAIN_RELAY_GAS_LIMIT;
        } else if (gasLimitType == CrossDomainMessageGasLimits.CloseFeePeriod) {
            return SETTING_CROSS_DOMAIN_FEE_PERIOD_CLOSE_GAS_LIMIT;
        } else {
            revert("Unknown gas limit type");
        }
    }

    function getCrossDomainMessageGasLimit(CrossDomainMessageGasLimits gasLimitType) internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, _getGasLimitSetting(gasLimitType));
    }

    function getTradingRewardsEnabled() internal view returns (bool) {
        return flexibleStorage().getBoolValue(SETTING_CONTRACT_NAME, SETTING_TRADING_REWARDS_ENABLED);
    }

    function getWaitingPeriodSecs() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_WAITING_PERIOD_SECS);
    }

    function getPriceDeviationThresholdFactor() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR);
    }

    function getIssuanceRatio() internal view returns (uint) {
        // lookup on flexible storage directly for gas savings (rather than via SystemSettings)
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ISSUANCE_RATIO);
    }

    function getFeePeriodDuration() internal view returns (uint) {
        // lookup on flexible storage directly for gas savings (rather than via SystemSettings)
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_FEE_PERIOD_DURATION);
    }

    function getTargetThreshold() internal view returns (uint) {
        // lookup on flexible storage directly for gas savings (rather than via SystemSettings)
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_TARGET_THRESHOLD);
    }

    function getLiquidationDelay() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_DELAY);
    }

    function getLiquidationRatio() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_RATIO);
    }

    function getLiquidationEscrowDuration() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_ESCROW_DURATION);
    }

    function getLiquidationPenalty() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_PENALTY);
    }

    function getSnxLiquidationPenalty() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_SNX_LIQUIDATION_PENALTY);
    }

    function getSelfLiquidationPenalty() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_SELF_LIQUIDATION_PENALTY);
    }

    function getFlagReward() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_FLAG_REWARD);
    }

    function getLiquidateReward() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATE_REWARD);
    }

    function getRateStalePeriod() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_RATE_STALE_PERIOD);
    }

    /* ========== Exchange Related Fees ========== */
    function getExchangeFeeRate(bytes32 currencyKey) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_EXCHANGE_FEE_RATE, currencyKey))
            );
    }

    /// @notice Get exchange dynamic fee related keys
    /// @return threshold, weight decay, rounds, and max fee
    function getExchangeDynamicFeeConfig() internal view returns (DynamicFeeConfig memory) {
        bytes32[] memory keys = new bytes32[](4);
        keys[0] = SETTING_EXCHANGE_DYNAMIC_FEE_THRESHOLD;
        keys[1] = SETTING_EXCHANGE_DYNAMIC_FEE_WEIGHT_DECAY;
        keys[2] = SETTING_EXCHANGE_DYNAMIC_FEE_ROUNDS;
        keys[3] = SETTING_EXCHANGE_MAX_DYNAMIC_FEE;
        uint[] memory values = flexibleStorage().getUIntValues(SETTING_CONTRACT_NAME, keys);
        return DynamicFeeConfig({threshold: values[0], weightDecay: values[1], rounds: values[2], maxFee: values[3]});
    }

    /* ========== End Exchange Related Fees ========== */

    function getMinimumStakeTime() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_MINIMUM_STAKE_TIME);
    }

    function getAggregatorWarningFlags() internal view returns (address) {
        return flexibleStorage().getAddressValue(SETTING_CONTRACT_NAME, SETTING_AGGREGATOR_WARNING_FLAGS);
    }

    function getDebtSnapshotStaleTime() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_DEBT_SNAPSHOT_STALE_TIME);
    }

    function getEtherWrapperMaxETH() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ETHER_WRAPPER_MAX_ETH);
    }

    function getEtherWrapperMintFeeRate() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ETHER_WRAPPER_MINT_FEE_RATE);
    }

    function getEtherWrapperBurnFeeRate() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ETHER_WRAPPER_BURN_FEE_RATE);
    }

    function getWrapperMaxTokenAmount(address wrapper) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_WRAPPER_MAX_TOKEN_AMOUNT, wrapper))
            );
    }

    function getWrapperMintFeeRate(address wrapper) internal view returns (int) {
        return
            flexibleStorage().getIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_WRAPPER_MINT_FEE_RATE, wrapper))
            );
    }

    function getWrapperBurnFeeRate(address wrapper) internal view returns (int) {
        return
            flexibleStorage().getIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_WRAPPER_BURN_FEE_RATE, wrapper))
            );
    }

    function getInteractionDelay(address collateral) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_INTERACTION_DELAY, collateral))
            );
    }

    function getCollapseFeeRate(address collateral) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_COLLAPSE_FEE_RATE, collateral))
            );
    }

    function getAtomicMaxVolumePerBlock() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ATOMIC_MAX_VOLUME_PER_BLOCK);
    }

    function getAtomicTwapWindow() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ATOMIC_TWAP_WINDOW);
    }

    function getAtomicEquivalentForDexPricing(bytes32 currencyKey) internal view returns (address) {
        return
            flexibleStorage().getAddressValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_ATOMIC_EQUIVALENT_FOR_DEX_PRICING, currencyKey))
            );
    }

    function getAtomicExchangeFeeRate(bytes32 currencyKey) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_ATOMIC_EXCHANGE_FEE_RATE, currencyKey))
            );
    }

    function getAtomicVolatilityConsiderationWindow(bytes32 currencyKey) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_ATOMIC_VOLATILITY_CONSIDERATION_WINDOW, currencyKey))
            );
    }

    function getAtomicVolatilityUpdateThreshold(bytes32 currencyKey) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_ATOMIC_VOLATILITY_UPDATE_THRESHOLD, currencyKey))
            );
    }

    function getPureChainlinkPriceForAtomicSwapsEnabled(bytes32 currencyKey) internal view returns (bool) {
        return
            flexibleStorage().getBoolValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_PURE_CHAINLINK_PRICE_FOR_ATOMIC_SWAPS_ENABLED, currencyKey))
            );
    }

    function getCrossChainSynthTransferEnabled(bytes32 currencyKey) internal view returns (uint) {
        return
            flexibleStorage().getUIntValue(
                SETTING_CONTRACT_NAME,
                keccak256(abi.encodePacked(SETTING_CROSS_SYNTH_TRANSFER_ENABLED, currencyKey))
            );
    }

    function getExchangeMaxDynamicFee() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_MAX_DYNAMIC_FEE);
    }

    function getExchangeDynamicFeeRounds() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_ROUNDS);
    }

    function getExchangeDynamicFeeThreshold() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_THRESHOLD);
    }

    function getExchangeDynamicFeeWeightDecay() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_WEIGHT_DECAY);
    }
}


// https://docs.synthetix.io/contracts/source/interfaces/ifeepool
interface IFeePool {
    // Views

    // solhint-disable-next-line func-name-mixedcase
    function FEE_ADDRESS() external view returns (address);

    function feesAvailable(address account) external view returns (uint, uint);

    function feesBurned(address account) external view returns (uint);

    function feesToBurn(address account) external view returns (uint);

    function feePeriodDuration() external view returns (uint);

    function isFeesClaimable(address account) external view returns (bool);

    function targetThreshold() external view returns (uint);

    function totalFeesAvailable() external view returns (uint);

    function totalFeesBurned() external view returns (uint);

    function totalRewardsAvailable() external view returns (uint);

    // Mutative Functions
    function claimFees() external returns (bool);

    function claimOnBehalf(address claimingForAddress) external returns (bool);

    function closeCurrentFeePeriod() external;

    function closeSecondary(uint snxBackedDebt, uint debtShareSupply) external;

    function recordFeePaid(uint sUSDAmount) external;

    function setRewardsToDistribute(uint amount) external;
}


/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}


// Libraries


// https://docs.synthetix.io/contracts/source/libraries/safedecimalmath
library SafeDecimalMath {
    using SafeMath for uint;

    /* Number of decimal places in the representations. */
    uint8 public constant decimals = 18;
    uint8 public constant highPrecisionDecimals = 27;

    /* The number representing 1.0. */
    uint public constant UNIT = 10**uint(decimals);

    /* The number representing 1.0 for higher fidelity numbers. */
    uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals);
    uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals);

    /**
     * @return Provides an interface to UNIT.
     */
    function unit() external pure returns (uint) {
        return UNIT;
    }

    /**
     * @return Provides an interface to PRECISE_UNIT.
     */
    function preciseUnit() external pure returns (uint) {
        return PRECISE_UNIT;
    }

    /**
     * @return The result of multiplying x and y, interpreting the operands as fixed-point
     * decimals.
     *
     * @dev A unit factor is divided out after the product of x and y is evaluated,
     * so that product must be less than 2**256. As this is an integer division,
     * the internal division always rounds down. This helps save on gas. Rounding
     * is more expensive on gas.
     */
    function multiplyDecimal(uint x, uint y) internal pure returns (uint) {
        /* Divide by UNIT to remove the extra factor introduced by the product. */
        return x.mul(y) / UNIT;
    }

    /**
     * @return The result of safely multiplying x and y, interpreting the operands
     * as fixed-point decimals of the specified precision unit.
     *
     * @dev The operands should be in the form of a the specified unit factor which will be
     * divided out after the product of x and y is evaluated, so that product must be
     * less than 2**256.
     *
     * Unlike multiplyDecimal, this function rounds the result to the nearest increment.
     * Rounding is useful when you need to retain fidelity for small decimal numbers
     * (eg. small fractions or percentages).
     */
    function _multiplyDecimalRound(
        uint x,
        uint y,
        uint precisionUnit
    ) private pure returns (uint) {
        /* Divide by UNIT to remove the extra factor introduced by the product. */
        uint quotientTimesTen = x.mul(y) / (precisionUnit / 10);

        if (quotientTimesTen % 10 >= 5) {
            quotientTimesTen += 10;
        }

        return quotientTimesTen / 10;
    }

    /**
     * @return The result of safely multiplying x and y, interpreting the operands
     * as fixed-point decimals of a precise unit.
     *
     * @dev The operands should be in the precise unit factor which will be
     * divided out after the product of x and y is evaluated, so that product must be
     * less than 2**256.
     *
     * Unlike multiplyDecimal, this function rounds the result to the nearest increment.
     * Rounding is useful when you need to retain fidelity for small decimal numbers
     * (eg. small fractions or percentages).
     */
    function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
        return _multiplyDecimalRound(x, y, PRECISE_UNIT);
    }

    /**
     * @return The result of safely multiplying x and y, interpreting the operands
     * as fixed-point decimals of a standard unit.
     *
     * @dev The operands should be in the standard unit factor which will be
     * divided out after the product of x and y is evaluated, so that product must be
     * less than 2**256.
     *
     * Unlike multiplyDecimal, this function rounds the result to the nearest increment.
     * Rounding is useful when you need to retain fidelity for small decimal numbers
     * (eg. small fractions or percentages).
     */
    function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) {
        return _multiplyDecimalRound(x, y, UNIT);
    }

    /**
     * @return The result of safely dividing x and y. The return value is a high
     * precision decimal.
     *
     * @dev y is divided after the product of x and the standard precision unit
     * is evaluated, so the product of x and UNIT must be less than 2**256. As
     * this is an integer division, the result is always rounded down.
     * This helps save on gas. Rounding is more expensive on gas.
     */
    function divideDecimal(uint x, uint y) internal pure returns (uint) {
        /* Reintroduce the UNIT factor that will be divided out by y. */
        return x.mul(UNIT).div(y);
    }

    /**
     * @return The result of safely dividing x and y. The return value is as a rounded
     * decimal in the precision unit specified in the parameter.
     *
     * @dev y is divided after the product of x and the specified precision unit
     * is evaluated, so the product of x and the specified precision unit must
     * be less than 2**256. The result is rounded to the nearest increment.
     */
    function _divideDecimalRound(
        uint x,
        uint y,
        uint precisionUnit
    ) private pure returns (uint) {
        uint resultTimesTen = x.mul(precisionUnit * 10).div(y);

        if (resultTimesTen % 10 >= 5) {
            resultTimesTen += 10;
        }

        return resultTimesTen / 10;
    }

    /**
     * @return The result of safely dividing x and y. The return value is as a rounded
     * standard precision decimal.
     *
     * @dev y is divided after the product of x and the standard precision unit
     * is evaluated, so the product of x and the standard precision unit must
     * be less than 2**256. The result is rounded to the nearest increment.
     */
    function divideDecimalRound(uint x, uint y) internal pure returns (uint) {
        return _divideDecimalRound(x, y, UNIT);
    }

    /**
     * @return The result of safely dividing x and y. The return value is as a rounded
     * high precision decimal.
     *
     * @dev y is divided after the product of x and the high precision unit
     * is evaluated, so the product of x and the high precision unit must
     * be less than 2**256. The result is rounded to the nearest increment.
     */
    function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
        return _divideDecimalRound(x, y, PRECISE_UNIT);
    }

    /**
     * @dev Convert a standard decimal representation to a high precision one.
     */
    function decimalToPreciseDecimal(uint i) internal pure returns (uint) {
        return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
    }

    /**
     * @dev Convert a high precision decimal to a standard decimal representation.
     */
    function preciseDecimalToDecimal(uint i) internal pure returns (uint) {
        uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10);

        if (quotientTimesTen % 10 >= 5) {
            quotientTimesTen += 10;
        }

        return quotientTimesTen / 10;
    }

    // Computes `a - b`, setting the value to 0 if b > a.
    function floorsub(uint a, uint b) internal pure returns (uint) {
        return b >= a ? 0 : a - b;
    }

    /* ---------- Utilities ---------- */
    /*
     * Absolute value of the input, returned as a signed number.
     */
    function signedAbs(int x) internal pure returns (int) {
        return x < 0 ? -x : x;
    }

    /*
     * Absolute value of the input, returned as an unsigned number.
     */
    function abs(int x) internal pure returns (uint) {
        return uint(signedAbs(x));
    }
}


interface AggregatorInterface {
  function latestAnswer() external view returns (int256);
  function latestTimestamp() external view returns (uint256);
  function latestRound() external view returns (uint256);
  function getAnswer(uint256 roundId) external view returns (int256);
  function getTimestamp(uint256 roundId) external view returns (uint256);

  event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
  event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}


interface AggregatorV3Interface {

  function decimals() external view returns (uint8);
  function description() external view returns (string memory);
  function version() external view returns (uint256);

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(uint80 _roundId)
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

}


/**
 * @title The V2 & V3 Aggregator Interface
 * @notice Solidity V0.5 does not allow interfaces to inherit from other
 * interfaces so this contract is a combination of v0.5 AggregatorInterface.sol
 * and v0.5 AggregatorV3Interface.sol.
 */
interface AggregatorV2V3Interface {
  //
  // V2 Interface:
  //
  function latestAnswer() external view returns (int256);
  function latestTimestamp() external view returns (uint256);
  function latestRound() external view returns (uint256);
  function getAnswer(uint256 roundId) external view returns (int256);
  function getTimestamp(uint256 roundId) external view returns (uint256);

  event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
  event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);

  //
  // V3 Interface:
  //
  function decimals() external view returns (uint8);
  function description() external view returns (string memory);
  function version() external view returns (uint256);

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(uint80 _roundId)
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

}


// https://docs.synthetix.io/contracts/source/interfaces/ierc20
interface IERC20 {
    // ERC20 Optional Views
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    // Views
    function totalSupply() external view returns (uint);

    function balanceOf(address owner) external view returns (uint);

    function allowance(address owner, address spender) external view returns (uint);

    // Mutative functions
    function transfer(address to, uint value) external returns (bool);

    function approve(address spender, uint value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint value
    ) external returns (bool);

    // Events
    event Transfer(address indexed from, address indexed to, uint value);

    event Approval(address indexed owner, address indexed spender, uint value);
}


// https://docs.synthetix.io/contracts/source/interfaces/isystemstatus
interface ISystemStatus {
    struct Status {
        bool canSuspend;
        bool canResume;
    }

    struct Suspension {
        bool suspended;
        // reason is an integer code,
        // 0 => no reason, 1 => upgrading, 2+ => defined by system usage
        uint248 reason;
    }

    // Views
    function accessControl(bytes32 section, address account) external view returns (bool canSuspend, bool canResume);

    function requireSystemActive() external view;

    function systemSuspended() external view returns (bool);

    function requireIssuanceActive() external view;

    function requireExchangeActive() external view;

    function requireFuturesActive() external view;

    function requireFuturesMarketActive(bytes32 marketKey) external view;

    function requireExchangeBetweenSynthsAllowed(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view;

    function requireSynthActive(bytes32 currencyKey) external view;

    function synthSuspended(bytes32 currencyKey) external view returns (bool);

    function requireSynthsActive(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view;

    function systemSuspension() external view returns (bool suspended, uint248 reason);

    function issuanceSuspension() external view returns (bool suspended, uint248 reason);

    function exchangeSuspension() external view returns (bool suspended, uint248 reason);

    function futuresSuspension() external view returns (bool suspended, uint248 reason);

    function synthExchangeSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason);

    function synthSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason);

    function futuresMarketSuspension(bytes32 marketKey) external view returns (bool suspended, uint248 reason);

    function getSynthExchangeSuspensions(bytes32[] calldata synths)
        external
        view
        returns (bool[] memory exchangeSuspensions, uint256[] memory reasons);

    function getSynthSuspensions(bytes32[] calldata synths)
        external
        view
        returns (bool[] memory suspensions, uint256[] memory reasons);

    function getFuturesMarketSuspensions(bytes32[] calldata marketKeys)
        external
        view
        returns (bool[] memory suspensions, uint256[] memory reasons);

    // Restricted functions
    function suspendIssuance(uint256 reason) external;

    function suspendSynth(bytes32 currencyKey, uint256 reason) external;

    function suspendFuturesMarket(bytes32 marketKey, uint256 reason) external;

    function updateAccessControl(
        bytes32 section,
        address account,
        bool canSuspend,
        bool canResume
    ) external;
}


interface IVirtualSynth {
    // Views
    function balanceOfUnderlying(address account) external view returns (uint);

    function rate() external view returns (uint);

    function readyToSettle() external view returns (bool);

    function secsLeftInWaitingPeriod() external view returns (uint);

    function settled() external view returns (bool);

    function synth() external view returns (ISynth);

    // Mutative functions
    function settle(address account) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/isynthetix
interface ISynthetix {
    // Views
    function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid);

    function availableCurrencyKeys() external view returns (bytes32[] memory);

    function availableSynthCount() external view returns (uint);

    function availableSynths(uint index) external view returns (ISynth);

    function collateral(address account) external view returns (uint);

    function collateralisationRatio(address issuer) external view returns (uint);

    function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint);

    function isWaitingPeriod(bytes32 currencyKey) external view returns (bool);

    function maxIssuableSynths(address issuer) external view returns (uint maxIssuable);

    function remainingIssuableSynths(address issuer)
        external
        view
        returns (
            uint maxIssuable,
            uint alreadyIssued,
            uint totalSystemDebt
        );

    function synths(bytes32 currencyKey) external view returns (ISynth);

    function synthsByAddress(address synthAddress) external view returns (bytes32);

    function totalIssuedSynths(bytes32 currencyKey) external view returns (uint);

    function totalIssuedSynthsExcludeOtherCollateral(bytes32 currencyKey) external view returns (uint);

    function transferableSynthetix(address account) external view returns (uint transferable);

    function getFirstNonZeroEscrowIndex(address account) external view returns (uint);

    // Mutative Functions
    function burnSynths(uint amount) external;

    function burnSynthsOnBehalf(address burnForAddress, uint amount) external;

    function burnSynthsToTarget() external;

    function burnSynthsToTargetOnBehalf(address burnForAddress) external;

    function exchange(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey
    ) external returns (uint amountReceived);

    function exchangeOnBehalf(
        address exchangeForAddress,
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey
    ) external returns (uint amountReceived);

    function exchangeWithTracking(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        address rewardAddress,
        bytes32 trackingCode
    ) external returns (uint amountReceived);

    function exchangeWithTrackingForInitiator(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        address rewardAddress,
        bytes32 trackingCode
    ) external returns (uint amountReceived);

    function exchangeOnBehalfWithTracking(
        address exchangeForAddress,
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        address rewardAddress,
        bytes32 trackingCode
    ) external returns (uint amountReceived);

    function exchangeWithVirtual(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        bytes32 trackingCode
    ) external returns (uint amountReceived, IVirtualSynth vSynth);

    function exchangeAtomically(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        bytes32 trackingCode,
        uint minAmount
    ) external returns (uint amountReceived);

    function issueMaxSynths() external;

    function issueMaxSynthsOnBehalf(address issueForAddress) external;

    function issueSynths(uint amount) external;

    function issueSynthsOnBehalf(address issueForAddress, uint amount) external;

    function mint() external returns (bool);

    function settle(bytes32 currencyKey)
        external
        returns (
            uint reclaimed,
            uint refunded,
            uint numEntries
        );

    // Liquidations
    function liquidateDelinquentAccount(address account) external returns (bool);

    function liquidateDelinquentAccountEscrowIndex(address account, uint escrowStartIndex) external returns (bool);

    function liquidateSelf() external returns (bool);

    // Restricted Functions

    function mintSecondary(address account, uint amount) external;

    function mintSecondaryRewards(uint amount) external;

    function burnSecondary(address account, uint amount) external;

    function revokeAllEscrow(address account) external;

    function migrateAccountBalances(address account) external returns (uint totalEscrowRevoked, uint totalLiquidBalance);
}


// https://docs.synthetix.io/contracts/source/interfaces/isynthetixdebtshare
interface ISynthetixDebtShare {
    // Views

    function currentPeriodId() external view returns (uint128);

    function allowance(address account, address spender) external view returns (uint);

    function balanceOf(address account) external view returns (uint);

    function balanceOfOnPeriod(address account, uint periodId) external view returns (uint);

    function totalSupply() external view returns (uint);

    function sharePercent(address account) external view returns (uint);

    function sharePercentOnPeriod(address account, uint periodId) external view returns (uint);

    // Mutative functions

    function takeSnapshot(uint128 id) external;

    function mintShare(address account, uint256 amount) external;

    function burnShare(address account, uint256 amount) external;

    function approve(address, uint256) external pure returns (bool);

    function transfer(address to, uint256 amount) external pure returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    function addAuthorizedBroker(address target) external;

    function removeAuthorizedBroker(address target) external;

    function addAuthorizedToSnapshot(address target) external;

    function removeAuthorizedToSnapshot(address target) external;
}


// Inheritance


// https://docs.synthetix.io/contracts/source/contracts/state
contract State is Owned {
    // the address of the contract that can modify variables
    // this can only be changed by the owner of this contract
    address public associatedContract;

    constructor(address _associatedContract) internal {
        // This contract is abstract, and thus cannot be instantiated directly
        require(owner != address(0), "Owner must be set");

        associatedContract = _associatedContract;
        emit AssociatedContractUpdated(_associatedContract);
    }

    /* ========== SETTERS ========== */

    // Change the associated contract to a new address
    function setAssociatedContract(address _associatedContract) external onlyOwner {
        associatedContract = _associatedContract;
        emit AssociatedContractUpdated(_associatedContract);
    }

    /* ========== MODIFIERS ========== */

    modifier onlyAssociatedContract {
        require(msg.sender == associatedContract, "Only the associated contract can perform this action");
        _;
    }

    /* ========== EVENTS ========== */

    event AssociatedContractUpdated(address associatedContract);
}


// Inheritance


// https://docs.synthetix.io/contracts/source/contracts/eternalstorage
/**
 * @notice  This contract is based on the code available from this blog
 * https://blog.colony.io/writing-upgradeable-contracts-in-solidity-6743f0eecc88/
 * Implements support for storing a keccak256 key and value pairs. It is the more flexible
 * and extensible option. This ensures data schema changes can be implemented without
 * requiring upgrades to the storage contract.
 */
contract EternalStorage is Owned, State {
    constructor(address _owner, address _associatedContract) public Owned(_owner) State(_associatedContract) {}

    /* ========== DATA TYPES ========== */
    mapping(bytes32 => uint) internal UIntStorage;
    mapping(bytes32 => string) internal StringStorage;
    mapping(bytes32 => address) internal AddressStorage;
    mapping(bytes32 => bytes) internal BytesStorage;
    mapping(bytes32 => bytes32) internal Bytes32Storage;
    mapping(bytes32 => bool) internal BooleanStorage;
    mapping(bytes32 => int) internal IntStorage;

    // UIntStorage;
    function getUIntValue(bytes32 record) external view returns (uint) {
        return UIntStorage[record];
    }

    function setUIntValue(bytes32 record, uint value) external onlyAssociatedContract {
        UIntStorage[record] = value;
    }

    function deleteUIntValue(bytes32 record) external onlyAssociatedContract {
        delete UIntStorage[record];
    }

    // StringStorage
    function getStringValue(bytes32 record) external view returns (string memory) {
        return StringStorage[record];
    }

    function setStringValue(bytes32 record, string calldata value) external onlyAssociatedContract {
        StringStorage[record] = value;
    }

    function deleteStringValue(bytes32 record) external onlyAssociatedContract {
        delete StringStorage[record];
    }

    // AddressStorage
    function getAddressValue(bytes32 record) external view returns (address) {
        return AddressStorage[record];
    }

    function setAddressValue(bytes32 record, address value) external onlyAssociatedContract {
        AddressStorage[record] = value;
    }

    function deleteAddressValue(bytes32 record) external onlyAssociatedContract {
        delete AddressStorage[record];
    }

    // BytesStorage
    function getBytesValue(bytes32 record) external view returns (bytes memory) {
        return BytesStorage[record];
    }

    function setBytesValue(bytes32 record, bytes calldata value) external onlyAssociatedContract {
        BytesStorage[record] = value;
    }

    function deleteBytesValue(bytes32 record) external onlyAssociatedContract {
        delete BytesStorage[record];
    }

    // Bytes32Storage
    function getBytes32Value(bytes32 record) external view returns (bytes32) {
        return Bytes32Storage[record];
    }

    function setBytes32Value(bytes32 record, bytes32 value) external onlyAssociatedContract {
        Bytes32Storage[record] = value;
    }

    function deleteBytes32Value(bytes32 record) external onlyAssociatedContract {
        delete Bytes32Storage[record];
    }

    // BooleanStorage
    function getBooleanValue(bytes32 record) external view returns (bool) {
        return BooleanStorage[record];
    }

    function setBooleanValue(bytes32 record, bool value) external onlyAssociatedContract {
        BooleanStorage[record] = value;
    }

    function deleteBooleanValue(bytes32 record) external onlyAssociatedContract {
        delete BooleanStorage[record];
    }

    // IntStorage
    function getIntValue(bytes32 record) external view returns (int) {
        return IntStorage[record];
    }

    function setIntValue(bytes32 record, int value) external onlyAssociatedContract {
        IntStorage[record] = value;
    }

    function deleteIntValue(bytes32 record) external onlyAssociatedContract {
        delete IntStorage[record];
    }
}


// Inheritance


// https://docs.synthetix.io/contracts/source/contracts/feepooleternalstorage
contract FeePoolEternalStorage is EternalStorage, LimitedSetup {
    bytes32 internal constant LAST_FEE_WITHDRAWAL = "last_fee_withdrawal";

    constructor(address _owner, address _feePool) public EternalStorage(_owner, _feePool) LimitedSetup(6 weeks) {}

    function importFeeWithdrawalData(address[] calldata accounts, uint[] calldata feePeriodIDs)
        external
        onlyOwner
        onlyDuringSetup
    {
        require(accounts.length == feePeriodIDs.length, "Length mismatch");

        for (uint8 i = 0; i < accounts.length; i++) {
            this.setUIntValue(keccak256(abi.encodePacked(LAST_FEE_WITHDRAWAL, accounts[i])), feePeriodIDs[i]);
        }
    }
}


pragma experimental ABIEncoderV2;


// https://docs.synthetix.io/contracts/source/interfaces/iexchanger
interface IExchanger {
    struct ExchangeEntrySettlement {
        bytes32 src;
        uint amount;
        bytes32 dest;
        uint reclaim;
        uint rebate;
        uint srcRoundIdAtPeriodEnd;
        uint destRoundIdAtPeriodEnd;
        uint timestamp;
    }

    struct ExchangeEntry {
        uint sourceRate;
        uint destinationRate;
        uint destinationAmount;
        uint exchangeFeeRate;
        uint exchangeDynamicFeeRate;
        uint roundIdForSrc;
        uint roundIdForDest;
        uint sourceAmountAfterSettlement;
    }

    // Views
    function calculateAmountAfterSettlement(
        address from,
        bytes32 currencyKey,
        uint amount,
        uint refunded
    ) external view returns (uint amountAfterSettlement);

    function isSynthRateInvalid(bytes32 currencyKey) external view returns (bool);

    function maxSecsLeftInWaitingPeriod(address account, bytes32 currencyKey) external view returns (uint);

    function settlementOwing(address account, bytes32 currencyKey)
        external
        view
        returns (
            uint reclaimAmount,
            uint rebateAmount,
            uint numEntries
        );

    function hasWaitingPeriodOrSettlementOwing(address account, bytes32 currencyKey) external view returns (bool);

    function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint);

    function dynamicFeeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey)
        external
        view
        returns (uint feeRate, bool tooVolatile);

    function getAmountsForExchange(
        uint sourceAmount,
        bytes32 sourceCurrencyKey,
        bytes32 destinationCurrencyKey
    )
        external
        view
        returns (
            uint amountReceived,
            uint fee,
            uint exchangeFeeRate
        );

    function priceDeviationThresholdFactor() external view returns (uint);

    function waitingPeriodSecs() external view returns (uint);

    function lastExchangeRate(bytes32 currencyKey) external view returns (uint);

    // Mutative functions
    function exchange(
        address exchangeForAddress,
        address from,
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        address destinationAddress,
        bool virtualSynth,
        address rewardAddress,
        bytes32 trackingCode
    ) external returns (uint amountReceived, IVirtualSynth vSynth);

    function exchangeAtomically(
        address from,
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        address destinationAddress,
        bytes32 trackingCode,
        uint minAmount
    ) external returns (uint amountReceived);

    function settle(address from, bytes32 currencyKey)
        external
        returns (
            uint reclaimed,
            uint refunded,
            uint numEntries
        );
}

// Used to have strongly-typed access to internal mutative functions in Synthetix
interface ISynthetixInternal {
    function emitExchangeTracking(
        bytes32 trackingCode,
        bytes32 toCurrencyKey,
        uint256 toAmount,
        uint256 fee
    ) external;

    function emitSynthExchange(
        address account,
        bytes32 fromCurrencyKey,
        uint fromAmount,
        bytes32 toCurrencyKey,
        uint toAmount,
        address toAddress
    ) external;

    function emitAtomicSynthExchange(
        address account,
        bytes32 fromCurrencyKey,
        uint fromAmount,
        bytes32 toCurrencyKey,
        uint toAmount,
        address toAddress
    ) external;

    function emitExchangeReclaim(
        address account,
        bytes32 currencyKey,
        uint amount
    ) external;

    function emitExchangeRebate(
        address account,
        bytes32 currencyKey,
        uint amount
    ) external;
}

interface IExchangerInternalDebtCache {
    function updateCachedSynthDebtsWithRates(bytes32[] calldata currencyKeys, uint[] calldata currencyRates) external;

    function updateCachedSynthDebts(bytes32[] calldata currencyKeys) external;
}


library VestingEntries {
    struct VestingEntry {
        uint64 endTime;
        uint256 escrowAmount;
    }
    struct VestingEntryWithID {
        uint64 endTime;
        uint256 escrowAmount;
        uint256 entryID;
    }
}

/// SIP-252: this is the interface for immutable V2 escrow (renamed with suffix Frozen).
/// These sources need to exist here and match on-chain frozen contracts for tests and reference.
/// the reason for the naming mess is that the immutable LiquidatorRewards expects a working
/// RewardEscrowV2 resolver entry for its getReward method, so the "new" (would be V3)
/// needs to be found at that entry for liq-rewards to function.
interface IRewardEscrowV2Frozen {
    // Views
    function balanceOf(address account) external view returns (uint);

    function numVestingEntries(address account) external view returns (uint);

    function totalEscrowedBalance() external view returns (uint);

    function totalEscrowedAccountBalance(address account) external view returns (uint);

    function totalVestedAccountBalance(address account) external view returns (uint);

    function getVestingQuantity(address account, uint256[] calldata entryIDs) external view returns (uint);

    function getVestingSchedules(
        address account,
        uint256 index,
        uint256 pageSize
    ) external view returns (VestingEntries.VestingEntryWithID[] memory);

    function getAccountVestingEntryIDs(
        address account,
        uint256 index,
        uint256 pageSize
    ) external view returns (uint256[] memory);

    function getVestingEntryClaimable(address account, uint256 entryID) external view returns (uint);

    function getVestingEntry(address account, uint256 entryID) external view returns (uint64, uint256);

    // Mutative functions
    function vest(uint256[] calldata entryIDs) external;

    function createEscrowEntry(
        address beneficiary,
        uint256 deposit,
        uint256 duration
    ) external;

    function appendVestingEntry(
        address account,
        uint256 quantity,
        uint256 duration
    ) external;

    function migrateVestingSchedule(address _addressToMigrate) external;

    function migrateAccountEscrowBalances(
        address[] calldata accounts,
        uint256[] calldata escrowBalances,
        uint256[] calldata vestedBalances
    ) external;

    // Account Merging
    function startMergingWindow() external;

    function mergeAccount(address accountToMerge, uint256[] calldata entryIDs) external;

    function nominateAccountToMerge(address account) external;

    function accountMergingIsOpen() external view returns (bool);

    // L2 Migration
    function importVestingEntries(
        address account,
        uint256 escrowedAmount,
        VestingEntries.VestingEntry[] calldata vestingEntries
    ) external;

    // Return amount of SNX transfered to SynthetixBridgeToOptimism deposit contract
    function burnForMigration(address account, uint256[] calldata entryIDs)
        external
        returns (uint256 escrowedAccountBalance, VestingEntries.VestingEntry[] memory vestingEntries);

    function nextEntryId() external view returns (uint);

    function vestingSchedules(address account, uint256 entryId) external view returns (VestingEntries.VestingEntry memory);

    function accountVestingEntryIDs(address account, uint256 index) external view returns (uint);

    //function totalEscrowedAccountBalance(address account) external view returns (uint);
    //function totalVestedAccountBalance(address account) external view returns (uint);
}


interface IRewardEscrowV2Storage {
    /// Views
    function numVestingEntries(address account) external view returns (uint);

    function totalEscrowedAccountBalance(address account) external view returns (uint);

    function totalVestedAccountBalance(address account) external view returns (uint);

    function totalEscrowedBalance() external view returns (uint);

    function nextEntryId() external view returns (uint);

    function vestingSchedules(address account, uint256 entryId) external view returns (VestingEntries.VestingEntry memory);

    function accountVestingEntryIDs(address account, uint256 index) external view returns (uint);

    /// Mutative
    function setZeroAmount(address account, uint entryId) external;

    function setZeroAmountUntilTarget(
        address account,
        uint startIndex,
        uint targetAmount
    )
        external
        returns (
            uint total,
            uint endIndex,
            uint lastEntryTime
        );

    function updateEscrowAccountBalance(address account, int delta) external;

    function updateVestedAccountBalance(address account, int delta) external;

    function updateTotalEscrowedBalance(int delta) external;

    function addVestingEntry(address account, VestingEntries.VestingEntry calldata entry) external returns (uint);

    // setFallbackRewardEscrow is used for configuration but not used by contracts
}

/// this should remain backwards compatible to IRewardEscrowV2Frozen
/// ideally this would be done by inheriting from that interface
/// but solidity v0.5 doesn't support interface inheritance
interface IRewardEscrowV2 {
    // Views
    function balanceOf(address account) external view returns (uint);

    function numVestingEntries(address account) external view returns (uint);

    function totalEscrowedBalance() external view returns (uint);

    function totalEscrowedAccountBalance(address account) external view returns (uint);

    function totalVestedAccountBalance(address account) external view returns (uint);

    function getVestingQuantity(address account, uint256[] calldata entryIDs) external view returns (uint);

    function getVestingSchedules(
        address account,
        uint256 index,
        uint256 pageSize
    ) external view returns (VestingEntries.VestingEntryWithID[] memory);

    function getAccountVestingEntryIDs(
        address account,
        uint256 index,
        uint256 pageSize
    ) external view returns (uint256[] memory);

    function getVestingEntryClaimable(address account, uint256 entryID) external view returns (uint);

    function getVestingEntry(address account, uint256 entryID) external view returns (uint64, uint256);

    // Mutative functions
    function vest(uint256[] calldata entryIDs) external;

    function createEscrowEntry(
        address beneficiary,
        uint256 deposit,
        uint256 duration
    ) external;

    function appendVestingEntry(
        address account,
        uint256 quantity,
        uint256 duration
    ) external;

    function migrateVestingSchedule(address _addressToMigrate) external;

    function migrateAccountEscrowBalances(
        address[] calldata accounts,
        uint256[] calldata escrowBalances,
        uint256[] calldata vestedBalances
    ) external;

    // Account Merging
    function startMergingWindow() external;

    function mergeAccount(address accountToMerge, uint256[] calldata entryIDs) external;

    function nominateAccountToMerge(address account) external;

    function accountMergingIsOpen() external view returns (bool);

    // L2 Migration
    function importVestingEntries(
        address account,
        uint256 escrowedAmount,
        VestingEntries.VestingEntry[] calldata vestingEntries
    ) external;

    // Return amount of SNX transfered to SynthetixBridgeToOptimism deposit contract
    function burnForMigration(address account, uint256[] calldata entryIDs)
        external
        returns (uint256 escrowedAccountBalance, VestingEntries.VestingEntry[] memory vestingEntries);

    function nextEntryId() external view returns (uint);

    function vestingSchedules(address account, uint256 entryId) external view returns (VestingEntries.VestingEntry memory);

    function accountVestingEntryIDs(address account, uint256 index) external view returns (uint);

    /// below are methods not available in IRewardEscrowV2Frozen

    // revoke entries for liquidations (access controlled to Synthetix)
    function revokeFrom(
        address account,
        address recipient,
        uint targetAmount,
        uint startIndex
    ) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/idelegateapprovals
interface IDelegateApprovals {
    // Views
    function canBurnFor(address authoriser, address delegate) external view returns (bool);

    function canIssueFor(address authoriser, address delegate) external view returns (bool);

    function canClaimFor(address authoriser, address delegate) external view returns (bool);

    function canExchangeFor(address authoriser, address delegate) external view returns (bool);

    // Mutative
    function approveAllDelegatePowers(address delegate) external;

    function removeAllDelegatePowers(address delegate) external;

    function approveBurnOnBehalf(address delegate) external;

    function removeBurnOnBehalf(address delegate) external;

    function approveIssueOnBehalf(address delegate) external;

    function removeIssueOnBehalf(address delegate) external;

    function approveClaimOnBehalf(address delegate) external;

    function removeClaimOnBehalf(address delegate) external;

    function approveExchangeOnBehalf(address delegate) external;

    function removeExchangeOnBehalf(address delegate) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/irewardsdistribution
interface IRewardsDistribution {
    // Structs
    struct DistributionData {
        address destination;
        uint amount;
    }

    // Views
    function authority() external view returns (address);

    function distributions(uint index) external view returns (address destination, uint amount); // DistributionData

    function distributionsLength() external view returns (uint);

    // Mutative Functions
    function distributeRewards(uint amount) external returns (bool);
}


interface ICollateralManager {
    // Manager information
    function hasCollateral(address collateral) external view returns (bool);

    function isSynthManaged(bytes32 currencyKey) external view returns (bool);

    // State information
    function long(bytes32 synth) external view returns (uint amount);

    function short(bytes32 synth) external view returns (uint amount);

    function totalLong() external view returns (uint susdValue, bool anyRateIsInvalid);

    function totalShort() external view returns (uint susdValue, bool anyRateIsInvalid);

    function getBorrowRate() external view returns (uint borrowRate, bool anyRateIsInvalid);

    function getShortRate(bytes32 synth) external view returns (uint shortRate, bool rateIsInvalid);

    function getRatesAndTime(uint index)
        external
        view
        returns (
            uint entryRate,
            uint lastRate,
            uint lastUpdated,
            uint newIndex
        );

    function getShortRatesAndTime(bytes32 currency, uint index)
        external
        view
        returns (
            uint entryRate,
            uint lastRate,
            uint lastUpdated,
            uint newIndex
        );

    function exceedsDebtLimit(uint amount, bytes32 currency) external view returns (bool canIssue, bool anyRateIsInvalid);

    function areSynthsAndCurrenciesSet(bytes32[] calldata requiredSynthNamesInResolver, bytes32[] calldata synthKeys)
        external
        view
        returns (bool);

    function areShortableSynthsSet(bytes32[] calldata requiredSynthNamesInResolver, bytes32[] calldata synthKeys)
        external
        view
        returns (bool);

    // Loans
    function getNewLoanId() external returns (uint id);

    // Manager mutative
    function addCollaterals(address[] calldata collaterals) external;

    function removeCollaterals(address[] calldata collaterals) external;

    function addSynths(bytes32[] calldata synthNamesInResolver, bytes32[] calldata synthKeys) external;

    function removeSynths(bytes32[] calldata synths, bytes32[] calldata synthKeys) external;

    function addShortableSynths(bytes32[] calldata requiredSynthNamesInResolver, bytes32[] calldata synthKeys) external;

    function removeShortableSynths(bytes32[] calldata synths) external;

    // State mutative

    function incrementLongs(bytes32 synth, uint amount) external;

    function decrementLongs(bytes32 synth, uint amount) external;

    function incrementShorts(bytes32 synth, uint amount) external;

    function decrementShorts(bytes32 synth, uint amount) external;

    function accrueInterest(
        uint interestIndex,
        bytes32 currency,
        bool isShort
    ) external returns (uint difference, uint index);

    function updateBorrowRatesCollateral(uint rate) external;

    function updateShortRatesCollateral(bytes32 currency, uint rate) external;
}


interface IWETH {
    // ERC20 Optional Views
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    // Views
    function totalSupply() external view returns (uint);

    function balanceOf(address owner) external view returns (uint);

    function allowance(address owner, address spender) external view returns (uint);

    // Mutative functions
    function transfer(address to, uint value) external returns (bool);

    function approve(address spender, uint value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint value
    ) external returns (bool);

    // WETH-specific functions.
    function deposit() external payable;

    function withdraw(uint amount) external;

    // Events
    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
    event Deposit(address indexed to, uint amount);
    event Withdrawal(address indexed to, uint amount);
}


// https://docs.synthetix.io/contracts/source/interfaces/ietherwrapper
contract IEtherWrapper {
    function mint(uint amount) external;

    function burn(uint amount) external;

    function distributeFees() external;

    function capacity() external view returns (uint);

    function getReserves() external view returns (uint);

    function totalIssuedSynths() external view returns (uint);

    function calculateMintFee(uint amount) public view returns (uint);

    function calculateBurnFee(uint amount) public view returns (uint);

    function maxETH() public view returns (uint256);

    function mintFeeRate() public view returns (uint256);

    function burnFeeRate() public view returns (uint256);

    function weth() public view returns (IWETH);
}


interface IFuturesMarketManager {
    function markets(uint index, uint pageSize) external view returns (address[] memory);

    function markets(
        uint index,
        uint pageSize,
        bool proxiedMarkets
    ) external view returns (address[] memory);

    function numMarkets() external view returns (uint);

    function numMarkets(bool proxiedMarkets) external view returns (uint);

    function allMarkets() external view returns (address[] memory);

    function allMarkets(bool proxiedMarkets) external view returns (address[] memory);

    function marketForKey(bytes32 marketKey) external view returns (address);

    function marketsForKeys(bytes32[] calldata marketKeys) external view returns (address[] memory);

    function totalDebt() external view returns (uint debt, bool isInvalid);

    function isEndorsed(address account) external view returns (bool);

    function allEndorsedAddresses() external view returns (address[] memory);

    function addEndorsedAddresses(address[] calldata addresses) external;

    function removeEndorsedAddresses(address[] calldata addresses) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/iwrapperfactory
interface IWrapperFactory {
    function isWrapper(address possibleWrapper) external view returns (bool);

    function createWrapper(
        IERC20 token,
        bytes32 currencyKey,
        bytes32 synthContractName
    ) external returns (address);

    function distributeFees() external;
}


interface ISynthetixBridgeToOptimism {
    function closeFeePeriod(uint snxBackedDebt, uint debtSharesSupply) external;

    function migrateEscrow(uint256[][] calldata entryIDs) external;

    function depositTo(address to, uint amount) external;

    function depositReward(uint amount) external;

    function depositAndMigrateEscrow(uint256 depositAmount, uint256[][] calldata entryIDs) external;
}


// Inheritance


// Libraries


// Internal references


// https://docs.synthetix.io/contracts/source/contracts/feepool
contract FeePool is Owned, Proxyable, LimitedSetup, MixinSystemSettings, IFeePool {
    using SafeMath for uint;
    using SafeDecimalMath for uint;

    bytes32 public constant CONTRACT_NAME = "FeePool";

    // Where fees are pooled in sUSD.
    address public constant FEE_ADDRESS = 0xfeEFEEfeefEeFeefEEFEEfEeFeefEEFeeFEEFEeF;

    // sUSD currencyKey. Fees stored and paid in sUSD
    bytes32 private sUSD = "sUSD";

    // This struct represents the issuance activity that's happened in a fee period.
    struct FeePeriod {
        uint64 feePeriodId;
        uint64 startTime;
        uint allNetworksSnxBackedDebt;
        uint allNetworksDebtSharesSupply;
        uint feesToDistribute;
        uint feesClaimed;
        uint rewardsToDistribute;
        uint rewardsClaimed;
    }

    // A staker(mintr) can claim from the previous fee period (7 days) only.
    // Fee Periods stored and managed from [0], such that [0] is always
    // the current active fee period which is not claimable until the
    // public function closeCurrentFeePeriod() is called closing the
    // current weeks collected fees. [1] is last weeks feeperiod
    uint8 public constant FEE_PERIOD_LENGTH = 2;

    FeePeriod[FEE_PERIOD_LENGTH] private _recentFeePeriods;
    uint256 private _currentFeePeriod;

    /* ========== ADDRESS RESOLVER CONFIGURATION ========== */

    bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus";
    bytes32 private constant CONTRACT_SYNTHETIXDEBTSHARE = "SynthetixDebtShare";
    bytes32 private constant CONTRACT_FEEPOOLETERNALSTORAGE = "FeePoolEternalStorage";
    bytes32 private constant CONTRACT_EXCHANGER = "Exchanger";
    bytes32 private constant CONTRACT_ISSUER = "Issuer";
    bytes32 private constant CONTRACT_REWARDESCROW_V2 = "RewardEscrowV2";
    bytes32 private constant CONTRACT_DELEGATEAPPROVALS = "DelegateApprovals";
    bytes32 private constant CONTRACT_COLLATERALMANAGER = "CollateralManager";
    bytes32 private constant CONTRACT_REWARDSDISTRIBUTION = "RewardsDistribution";
    bytes32 private constant CONTRACT_ETHER_WRAPPER = "EtherWrapper";
    bytes32 private constant CONTRACT_FUTURES_MARKET_MANAGER = "FuturesMarketManager";
    bytes32 private constant CONTRACT_WRAPPER_FACTORY = "WrapperFactory";

    bytes32 private constant CONTRACT_SYNTHETIX_BRIDGE_TO_OPTIMISM = "SynthetixBridgeToOptimism";
    bytes32 private constant CONTRACT_SYNTHETIX_BRIDGE_TO_BASE = "SynthetixBridgeToBase";

    bytes32 private constant CONTRACT_EXT_AGGREGATOR_ISSUED_SYNTHS = "ext:AggregatorIssuedSynths";
    bytes32 private constant CONTRACT_EXT_AGGREGATOR_DEBT_RATIO = "ext:AggregatorDebtRatio";

    /* ========== ETERNAL STORAGE CONSTANTS ========== */

    bytes32 private constant LAST_FEE_WITHDRAWAL = "last_fee_withdrawal";

    constructor(
        address payable _proxy,
        address _owner,
        address _resolver
    ) public Owned(_owner) Proxyable(_proxy) LimitedSetup(3 weeks) MixinSystemSettings(_resolver) {
        // Set our initial fee period
        _recentFeePeriodsStorage(0).feePeriodId = 1;
        _recentFeePeriodsStorage(0).startTime = uint64(block.timestamp);
    }

    /* ========== VIEWS ========== */
    function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
        bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired();
        bytes32[] memory newAddresses = new bytes32[](14);
        newAddresses[0] = CONTRACT_SYSTEMSTATUS;
        newAddresses[1] = CONTRACT_SYNTHETIXDEBTSHARE;
        newAddresses[2] = CONTRACT_FEEPOOLETERNALSTORAGE;
        newAddresses[3] = CONTRACT_EXCHANGER;
        newAddresses[4] = CONTRACT_ISSUER;
        newAddresses[5] = CONTRACT_REWARDESCROW_V2;
        newAddresses[6] = CONTRACT_DELEGATEAPPROVALS;
        newAddresses[7] = CONTRACT_REWARDSDISTRIBUTION;
        newAddresses[8] = CONTRACT_COLLATERALMANAGER;
        newAddresses[9] = CONTRACT_WRAPPER_FACTORY;
        newAddresses[10] = CONTRACT_ETHER_WRAPPER;
        newAddresses[11] = CONTRACT_EXT_AGGREGATOR_ISSUED_SYNTHS;
        newAddresses[12] = CONTRACT_EXT_AGGREGATOR_DEBT_RATIO;
        newAddresses[13] = CONTRACT_FUTURES_MARKET_MANAGER;
        addresses = combineArrays(existingAddresses, newAddresses);
    }

    function systemStatus() internal view returns (ISystemStatus) {
        return ISystemStatus(requireAndGetAddress(CONTRACT_SYSTEMSTATUS));
    }

    function synthetixDebtShare() internal view returns (ISynthetixDebtShare) {
        return ISynthetixDebtShare(requireAndGetAddress(CONTRACT_SYNTHETIXDEBTSHARE));
    }

    function feePoolEternalStorage() internal view returns (FeePoolEternalStorage) {
        return FeePoolEternalStorage(requireAndGetAddress(CONTRACT_FEEPOOLETERNALSTORAGE));
    }

    function exchanger() internal view returns (IExchanger) {
        return IExchanger(requireAndGetAddress(CONTRACT_EXCHANGER));
    }

    function collateralManager() internal view returns (ICollateralManager) {
        return ICollateralManager(requireAndGetAddress(CONTRACT_COLLATERALMANAGER));
    }

    function issuer() internal view returns (IIssuer) {
        return IIssuer(requireAndGetAddress(CONTRACT_ISSUER));
    }

    function rewardEscrowV2() internal view returns (IRewardEscrowV2) {
        return IRewardEscrowV2(requireAndGetAddress(CONTRACT_REWARDESCROW_V2));
    }

    function delegateApprovals() internal view returns (IDelegateApprovals) {
        return IDelegateApprovals(requireAndGetAddress(CONTRACT_DELEGATEAPPROVALS));
    }

    function rewardsDistribution() internal view returns (IRewardsDistribution) {
        return IRewardsDistribution(requireAndGetAddress(CONTRACT_REWARDSDISTRIBUTION));
    }

    function etherWrapper() internal view returns (IEtherWrapper) {
        return IEtherWrapper(requireAndGetAddress(CONTRACT_ETHER_WRAPPER));
    }

    function futuresMarketManager() internal view returns (IFuturesMarketManager) {
        return IFuturesMarketManager(requireAndGetAddress(CONTRACT_FUTURES_MARKET_MANAGER));
    }

    function wrapperFactory() internal view returns (IWrapperFactory) {
        return IWrapperFactory(requireAndGetAddress(CONTRACT_WRAPPER_FACTORY));
    }

    function issuanceRatio() external view returns (uint) {
        return getIssuanceRatio();
    }

    function feePeriodDuration() external view returns (uint) {
        return getFeePeriodDuration();
    }

    function targetThreshold() external view returns (uint) {
        return getTargetThreshold();
    }

    function allNetworksSnxBackedDebt() public view returns (uint256 debt, uint256 updatedAt) {
        (, int256 rawData, , uint timestamp, ) =
            AggregatorV2V3Interface(requireAndGetAddress(CONTRACT_EXT_AGGREGATOR_ISSUED_SYNTHS)).latestRoundData();

        debt = uint(rawData);
        updatedAt = timestamp;
    }

    function allNetworksDebtSharesSupply() public view returns (uint256 sharesSupply, uint256 updatedAt) {
        (, int256 rawIssuedSynths, , uint issuedSynthsUpdatedAt, ) =
            AggregatorV2V3Interface(requireAndGetAddress(CONTRACT_EXT_AGGREGATOR_ISSUED_SYNTHS)).latestRoundData();

        (, int256 rawRatio, , uint ratioUpdatedAt, ) =
            AggregatorV2V3Interface(requireAndGetAddress(CONTRACT_EXT_AGGREGATOR_DEBT_RATIO)).latestRoundData();

        uint debt = uint(rawIssuedSynths);
        sharesSupply = rawRatio == 0 ? 0 : debt.divideDecimalRoundPrecise(uint(rawRatio));
        updatedAt = issuedSynthsUpdatedAt < ratioUpdatedAt ? issuedSynthsUpdatedAt : ratioUpdatedAt;
    }

    function recentFeePeriods(uint index)
        external
        view
        returns (
            uint64 feePeriodId,
            uint64 unused, // required post 185 for api compatibility
            uint64 startTime,
            uint feesToDistribute,
            uint feesClaimed,
            uint rewardsToDistribute,
            uint rewardsClaimed
        )
    {
        FeePeriod memory feePeriod = _recentFeePeriodsStorage(index);
        return (
            feePeriod.feePeriodId,
            0,
            feePeriod.startTime,
            feePeriod.feesToDistribute,
            feePeriod.feesClaimed,
            feePeriod.rewardsToDistribute,
            feePeriod.rewardsClaimed
        );
    }

    function _recentFeePeriodsStorage(uint index) internal view returns (FeePeriod storage) {
        return _recentFeePeriods[(_currentFeePeriod + index) % FEE_PERIOD_LENGTH];
    }

    /**
     * @notice The Exchanger contract informs us when fees are paid.
     * @param amount susd amount in fees being paid.
     */
    function recordFeePaid(uint amount) external onlyInternalContracts {
        // Keep track off fees in sUSD in the open fee pool period.
        _recentFeePeriodsStorage(0).feesToDistribute = _recentFeePeriodsStorage(0).feesToDistribute.add(amount);
    }

    /**
     * @notice The RewardsDistribution contract informs us how many SNX rewards are sent to RewardEscrow to be claimed.
     */
    function setRewardsToDistribute(uint amount) external optionalProxy {
        require(messageSender == address(rewardsDistribution()), "RewardsDistribution only");
        // Add the amount of SNX rewards to distribute on top of any rolling unclaimed amount
        _recentFeePeriodsStorage(0).rewardsToDistribute = _recentFeePeriodsStorage(0).rewardsToDistribute.add(amount);
    }

    /**
     * @notice Close the current fee period and start a new one.
     */
    function closeCurrentFeePeriod() external issuanceActive {
        require(getFeePeriodDuration() > 0, "Fee Period Duration not set");
        require(_recentFeePeriodsStorage(0).startTime <= (now - getFeePeriodDuration()), "Too early to close fee period");

        // get current oracle values
        (uint snxBackedDebt, ) = allNetworksSnxBackedDebt();
        (uint debtSharesSupply, ) = allNetworksDebtSharesSupply();

        // close on this chain
        _closeSecondary(snxBackedDebt, debtSharesSupply);

        // inform other chain of the chosen values
        ISynthetixBridgeToOptimism(
            resolver.requireAndGetAddress(
                CONTRACT_SYNTHETIX_BRIDGE_TO_OPTIMISM,
                "Missing contract: SynthetixBridgeToOptimism"
            )
        )
            .closeFeePeriod(snxBackedDebt, debtSharesSupply);
    }

    function closeSecondary(uint allNetworksSnxBackedDebt, uint allNetworksDebtSharesSupply) external onlyRelayer {
        _closeSecondary(allNetworksSnxBackedDebt, allNetworksDebtSharesSupply);
    }

    /**
     * @notice Close the current fee period and start a new one.
     */
    function _closeSecondary(uint allNetworksSnxBackedDebt, uint allNetworksDebtSharesSupply) internal {
        etherWrapper().distributeFees();
        wrapperFactory().distributeFees();

        // before closing the current fee period, set the recorded snxBackedDebt and debtSharesSupply
        _recentFeePeriodsStorage(0).allNetworksDebtSharesSupply = allNetworksDebtSharesSupply;
        _recentFeePeriodsStorage(0).allNetworksSnxBackedDebt = allNetworksSnxBackedDebt;

        // Note:  periodClosing is the current period & periodToRollover is the last open claimable period
        FeePeriod storage periodClosing = _recentFeePeriodsStorage(0);
        FeePeriod storage periodToRollover = _recentFeePeriodsStorage(FEE_PERIOD_LENGTH - 1);

        // Any unclaimed fees from the last period in the array roll back one period.
        // Because of the subtraction here, they're effectively proportionally redistributed to those who
        // have already claimed from the old period, available in the new period.
        // The subtraction is important so we don't create a ticking time bomb of an ever growing
        // number of fees that can never decrease and will eventually overflow at the end of the fee pool.
        _recentFeePeriodsStorage(0).feesToDistribute = periodToRollover
            .feesToDistribute
            .sub(periodToRollover.feesClaimed)
            .add(periodClosing.feesToDistribute);
        _recentFeePeriodsStorage(0).rewardsToDistribute = periodToRollover
            .rewardsToDistribute
            .sub(periodToRollover.rewardsClaimed)
            .add(periodClosing.rewardsToDistribute);

        // Note: As of SIP-255, all sUSD fee are now automatically burned and are effectively shared amongst stakers in the form of reduced debt.
        if (_recentFeePeriodsStorage(0).feesToDistribute > 0) {
            issuer().burnSynthsWithoutDebt(sUSD, FEE_ADDRESS, _recentFeePeriodsStorage(0).feesToDistribute);

            // Mark the burnt fees as claimed.
            _recentFeePeriodsStorage(0).feesClaimed = _recentFeePeriodsStorage(0).feesToDistribute;
        }

        // Shift the previous fee periods across to make room for the new one.
        _currentFeePeriod = _currentFeePeriod.add(FEE_PERIOD_LENGTH).sub(1).mod(FEE_PERIOD_LENGTH);

        // Clear the first element of the array to make sure we don't have any stale values.
        delete _recentFeePeriods[_currentFeePeriod];

        // Open up the new fee period.
        // periodID is set to the current timestamp for compatibility with other systems taking snapshots on the debt shares
        uint newFeePeriodId = block.timestamp;
        _recentFeePeriodsStorage(0).feePeriodId = uint64(newFeePeriodId);
        _recentFeePeriodsStorage(0).startTime = uint64(block.timestamp);

        // Inform Issuer to start recording for the new fee period
        issuer().setCurrentPeriodId(uint128(newFeePeriodId));

        emitFeePeriodClosed(_recentFeePeriodsStorage(1).feePeriodId);
    }

    /**
     * @notice Claim fees for last period when available or not already withdrawn.
     */
    function claimFees() external issuanceActive optionalProxy returns (bool) {
        return _claimFees(messageSender);
    }

    /**
     * @notice Delegated claimFees(). Call from the deletegated address
     * and the fees will be sent to the claimingForAddress.
     * approveClaimOnBehalf() must be called first to approve the deletage address
     * @param claimingForAddress The account you are claiming fees for
     */
    function claimOnBehalf(address claimingForAddress) external issuanceActive optionalProxy returns (bool) {
        require(delegateApprovals().canClaimFor(claimingForAddress, messageSender), "Not approved to claim on behalf");

        return _claimFees(claimingForAddress);
    }

    /**
     * Note: As of SIP-255, all sUSD fees are burned at the closure of the fee period and are no longer claimable.
     * @notice Send the rewards to claiming address.
     * @param claimingAddress The address to send the rewards to.
     */
    function _claimFees(address claimingAddress) internal returns (bool) {
        uint rewardsPaid = 0;
        uint feesPaid = 0;
        uint availableFees;
        uint availableRewards;

        // Address won't be able to claim fees if it is too far below the target c-ratio.
        // It will need to burn synths then try claiming again.
        (bool feesClaimable, bool anyRateIsInvalid) = _isFeesClaimableAndAnyRatesInvalid(claimingAddress);

        require(feesClaimable, "C-Ratio below penalty threshold");

        require(!anyRateIsInvalid, "A synth or SNX rate is invalid");

        // Get the claimingAddress available fees and rewards
        (availableFees, availableRewards) = feesAvailable(claimingAddress);

        require(
            availableFees > 0 || availableRewards > 0,
            "No fees or rewards available for period, or fees already claimed"
        );

        // Record the address has claimed for this period
        _setLastFeeWithdrawal(claimingAddress, _recentFeePeriodsStorage(1).feePeriodId);

        // Mark the fees as paid since they were already burned.
        feesPaid = availableFees;

        if (availableRewards > 0) {
            // Record the reward payment in our recentFeePeriods
            rewardsPaid = _recordRewardPayment(availableRewards);

            // Send them their rewards
            _payRewards(claimingAddress, rewardsPaid);
        }

        emitFeesClaimed(claimingAddress, feesPaid, rewardsPaid);

        return true;
    }

    /**
     * @notice Admin function to import the FeePeriod data from the previous contract
     */
    function importFeePeriod(
        uint feePeriodIndex,
        uint feePeriodId,
        uint startTime,
        uint feesToDistribute,
        uint feesClaimed,
        uint rewardsToDistribute,
        uint rewardsClaimed
    ) external optionalProxy_onlyOwner onlyDuringSetup {
        require(feePeriodIndex < FEE_PERIOD_LENGTH, "invalid fee period index");

        _recentFeePeriods[feePeriodIndex] = FeePeriod({
            feePeriodId: uint64(feePeriodId),
            startTime: uint64(startTime),
            feesToDistribute: feesToDistribute,
            feesClaimed: feesClaimed,
            rewardsToDistribute: rewardsToDistribute,
            rewardsClaimed: rewardsClaimed,
            allNetworksSnxBackedDebt: 0,
            allNetworksDebtSharesSupply: 0
        });

        // make sure recording is aware of the actual period id
        if (feePeriodIndex == 0) {
            issuer().setCurrentPeriodId(uint128(feePeriodId));
        }
    }

    /**
     * @notice Record the reward payment in our recentFeePeriods.
     * @param snxAmount The amount of SNX tokens.
     */
    function _recordRewardPayment(uint snxAmount) internal returns (uint) {
        // Don't assign to the parameter
        uint remainingToAllocate = snxAmount;

        uint rewardPaid;

        // Start at the oldest period and record the amount, moving to newer periods
        // until we've exhausted the amount.
        // The condition checks for overflow because we're going to 0 with an unsigned int.
        for (uint i = FEE_PERIOD_LENGTH - 1; i < FEE_PERIOD_LENGTH; i--) {
            uint toDistribute =
                _recentFeePeriodsStorage(i).rewardsToDistribute.sub(_recentFeePeriodsStorage(i).rewardsClaimed);

            if (toDistribute > 0) {
                // Take the smaller of the amount left to claim in the period and the amount we need to allocate
                uint amountInPeriod = toDistribute < remainingToAllocate ? toDistribute : remainingToAllocate;

                _recentFeePeriodsStorage(i).rewardsClaimed = _recentFeePeriodsStorage(i).rewardsClaimed.add(amountInPeriod);
                remainingToAllocate = remainingToAllocate.sub(amountInPeriod);
                rewardPaid = rewardPaid.add(amountInPeriod);

                // No need to continue iterating if we've recorded the whole amount;
                if (remainingToAllocate == 0) return rewardPaid;
            }
        }
        return rewardPaid;
    }

    /**
     * @notice Send the rewards to claiming address - will be locked in rewardEscrow.
     * @param account The address to send the fees to.
     * @param snxAmount The amount of SNX.
     */
    function _payRewards(address account, uint snxAmount) internal notFeeAddress(account) {
        /* Escrow the tokens for 1 year. */
        uint escrowDuration = 52 weeks;

        // Record vesting entry for claiming address and amount
        // SNX already minted to rewardEscrow balance
        rewardEscrowV2().appendVestingEntry(account, snxAmount, escrowDuration);
    }

    /**
     * @notice The total fees available in the system to be withdrawn in sUSD.
     */
    function totalFeesAvailable() external view returns (uint) {
        uint totalFees = 0;

        // Fees in fee period [0] are not yet available for withdrawal
        for (uint i = 1; i < FEE_PERIOD_LENGTH; i++) {
            totalFees = totalFees.add(_recentFeePeriodsStorage(i).feesToDistribute);
            totalFees = totalFees.sub(_recentFeePeriodsStorage(i).feesClaimed);
        }

        return totalFees;
    }

    /**
     * @notice The total fees that were already burned (i.e. claimed) in the previous fee period [1].
     */
    function totalFeesBurned() external view returns (uint) {
        return _recentFeePeriodsStorage(1).feesClaimed;
    }

    /**
     * @notice The total SNX rewards available in the system to be withdrawn
     */
    function totalRewardsAvailable() external view returns (uint) {
        uint totalRewards = 0;

        // Rewards in fee period [0] are not yet available for withdrawal
        for (uint i = 1; i < FEE_PERIOD_LENGTH; i++) {
            totalRewards = totalRewards.add(_recentFeePeriodsStorage(i).rewardsToDistribute);
            totalRewards = totalRewards.sub(_recentFeePeriodsStorage(i).rewardsClaimed);
        }

        return totalRewards;
    }

    /**
     * @notice The fees available to be withdrawn by a specific account, priced in sUSD
     * @dev Returns two amounts, one for fees and one for SNX rewards
     */
    function feesAvailable(address account) public view returns (uint, uint) {
        // Add up the fees
        uint[FEE_PERIOD_LENGTH][2] memory userFees = feesByPeriod(account);

        uint totalFees = 0;
        uint totalRewards = 0;

        // Fees & Rewards in fee period [0] are not yet available for withdrawal
        for (uint i = 1; i < FEE_PERIOD_LENGTH; i++) {
            totalFees = totalFees.add(userFees[i][0]);
            totalRewards = totalRewards.add(userFees[i][1]);
        }

        // And convert totalFees to sUSD
        // Return totalRewards as is in SNX amount
        return (totalFees, totalRewards);
    }

    /**
     * @notice The total amount of fees burned for a specific account in the previous period [1].
     * Note: Fees in the current fee period [0] are not yet burned.
     */
    function feesBurned(address account) public view returns (uint) {
        uint[FEE_PERIOD_LENGTH][2] memory userFees = feesByPeriod(account);
        return userFees[1][0];
    }

    /**
     * @notice The amount of fees to be burned for an account during the current fee period [0].
     * Note: this returns an approximate value based on the current system rate. Any changes in debt shares may affect the outcome of the final amount.
     * This also does not consider pending fees in the wrappers since they are distributed at fee period close.
     */
    function feesToBurn(address account) public view returns (uint feesFromPeriod) {
        ISynthetixDebtShare sds = synthetixDebtShare();
        uint userOwnershipPercentage = sds.sharePercent(account);
        (feesFromPeriod, ) = _feesAndRewardsFromPeriod(0, userOwnershipPercentage);
        return feesFromPeriod;
    }

    function _isFeesClaimableAndAnyRatesInvalid(address account) internal view returns (bool, bool) {
        // Threshold is calculated from ratio % above the target ratio (issuanceRatio).
        //  0  <  10%:   Claimable
        // 10% > above:  Unable to claim
        (uint ratio, bool anyRateIsInvalid) = issuer().collateralisationRatioAndAnyRatesInvalid(account);
        uint targetRatio = getIssuanceRatio();

        // Claimable if collateral ratio below target ratio
        if (ratio < targetRatio) {
            return (true, anyRateIsInvalid);
        }

        // Calculate the threshold for collateral ratio before fees can't be claimed.
        uint ratio_threshold = targetRatio.multiplyDecimal(SafeDecimalMath.unit().add(getTargetThreshold()));

        // Not claimable if collateral ratio above threshold
        if (ratio > ratio_threshold) {
            return (false, anyRateIsInvalid);
        }

        return (true, anyRateIsInvalid);
    }

    function isFeesClaimable(address account) external view returns (bool feesClaimable) {
        (feesClaimable, ) = _isFeesClaimableAndAnyRatesInvalid(account);
    }

    /**
     * @notice Calculates fees by period for an account, priced in sUSD
     * @param account The address you want to query the fees for
     */
    function feesByPeriod(address account) public view returns (uint[FEE_PERIOD_LENGTH][2] memory results) {
        // What's the user's debt entry index and the debt they owe to the system at current feePeriod
        uint userOwnershipPercentage;
        ISynthetixDebtShare sds = synthetixDebtShare();

        userOwnershipPercentage = sds.sharePercent(account);

        // The [0] fee period is not yet ready to claim, but it is a fee period that they can have
        // fees owing for, so we need to report on it anyway.
        uint feesFromPeriod;
        uint rewardsFromPeriod;
        (feesFromPeriod, rewardsFromPeriod) = _feesAndRewardsFromPeriod(0, userOwnershipPercentage);

        results[0][0] = feesFromPeriod;
        results[0][1] = rewardsFromPeriod;

        // Retrieve user's last fee claim by periodId
        uint lastFeeWithdrawal = getLastFeeWithdrawal(account);

        // Go through our fee periods from the oldest feePeriod[FEE_PERIOD_LENGTH - 1] and figure out what we owe them.
        // Condition checks for periods > 0
        for (uint i = FEE_PERIOD_LENGTH - 1; i > 0; i--) {
            uint64 periodId = _recentFeePeriodsStorage(i).feePeriodId;
            if (lastFeeWithdrawal < periodId) {
                userOwnershipPercentage = sds.sharePercentOnPeriod(account, uint(periodId));

                (feesFromPeriod, rewardsFromPeriod) = _feesAndRewardsFromPeriod(i, userOwnershipPercentage);

                results[i][0] = feesFromPeriod;
                results[i][1] = rewardsFromPeriod;
            }
        }
    }

    /**
     * @notice ownershipPercentage is a high precision decimals uint based on
     * wallet's debtPercentage. Gives a precise amount of the feesToDistribute
     * for fees in the period. Precision factor is removed before results are
     * returned.
     * @dev The reported fees owing for the current period [0] are just a
     * running balance until the fee period closes
     */
    function _feesAndRewardsFromPeriod(uint period, uint ownershipPercentage) internal view returns (uint, uint) {
        // If it's zero, they haven't issued, and they have no fees OR rewards.
        if (ownershipPercentage == 0) return (0, 0);

        FeePeriod storage fp = _recentFeePeriodsStorage(period);

        // Calculate their percentage of the fees / rewards in this period
        // This is a high precision integer.
        uint feesFromPeriod = fp.feesToDistribute.multiplyDecimal(ownershipPercentage);

        uint rewardsFromPeriod = fp.rewardsToDistribute.multiplyDecimal(ownershipPercentage);

        return (feesFromPeriod, rewardsFromPeriod);
    }

    function effectiveDebtRatioForPeriod(address account, uint period) external view returns (uint) {
        // if period is not closed yet, or outside of the fee period range, return 0 instead of reverting
        if (period == 0 || period >= FEE_PERIOD_LENGTH) {
            return 0;
        }

        // If the period being checked is uninitialised then return 0. This is only at the start of the system.
        if (_recentFeePeriodsStorage(period - 1).startTime == 0) return 0;

        return synthetixDebtShare().sharePercentOnPeriod(account, uint(_recentFeePeriods[period].feePeriodId));
    }

    /**
     * @notice Get the feePeriodID of the last claim this account made
     * @param _claimingAddress account to check the last fee period ID claim for
     * @return uint of the feePeriodID this account last claimed
     */
    function getLastFeeWithdrawal(address _claimingAddress) public view returns (uint) {
        return feePoolEternalStorage().getUIntValue(keccak256(abi.encodePacked(LAST_FEE_WITHDRAWAL, _claimingAddress)));
    }

    /**
     * @notice Calculate the collateral ratio before user is blocked from claiming.
     */
    function getPenaltyThresholdRatio() public view returns (uint) {
        return getIssuanceRatio().multiplyDecimal(SafeDecimalMath.unit().add(getTargetThreshold()));
    }

    /**
     * @notice Set the feePeriodID of the last claim this account made
     * @param _claimingAddress account to set the last feePeriodID claim for
     * @param _feePeriodID the feePeriodID this account claimed fees for
     */
    function _setLastFeeWithdrawal(address _claimingAddress, uint _feePeriodID) internal {
        feePoolEternalStorage().setUIntValue(
            keccak256(abi.encodePacked(LAST_FEE_WITHDRAWAL, _claimingAddress)),
            _feePeriodID
        );
    }

    /* ========== Modifiers ========== */

    function _isInternalContract(address account) internal view returns (bool) {
        return
            account == address(exchanger()) ||
            issuer().synthsByAddress(account) != bytes32(0) ||
            collateralManager().hasCollateral(account) ||
            account == address(futuresMarketManager()) ||
            account == address(wrapperFactory()) ||
            account == address(etherWrapper());
    }

    modifier onlyInternalContracts {
        require(_isInternalContract(msg.sender), "Only Internal Contracts");
        _;
    }

    modifier onlyRelayer {
        require(
            msg.sender == address(this) || msg.sender == resolver.getAddress(CONTRACT_SYNTHETIX_BRIDGE_TO_BASE),
            "Only valid relayer can call"
        );
        _;
    }

    modifier notFeeAddress(address account) {
        require(account != FEE_ADDRESS, "Fee address not allowed");
        _;
    }

    modifier issuanceActive() {
        systemStatus().requireIssuanceActive();
        _;
    }

    /* ========== Proxy Events ========== */

    event FeePeriodClosed(uint feePeriodId);
    bytes32 private constant FEEPERIODCLOSED_SIG = keccak256("FeePeriodClosed(uint256)");

    function emitFeePeriodClosed(uint feePeriodId) internal {
        proxy._emit(abi.encode(feePeriodId), 1, FEEPERIODCLOSED_SIG, 0, 0, 0);
    }

    event FeesClaimed(address account, uint sUSDAmount, uint snxRewards);
    bytes32 private constant FEESCLAIMED_SIG = keccak256("FeesClaimed(address,uint256,uint256)");

    function emitFeesClaimed(
        address account,
        uint sUSDAmount,
        uint snxRewards
    ) internal {
        proxy._emit(abi.encode(account, sUSDAmount, snxRewards), 1, FEESCLAIMED_SIG, 0, 0, 0);
    }
}

Contract ABI

[{"inputs":[{"internalType":"address payable","name":"_proxy","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_resolver","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feePeriodId","type":"uint256"}],"name":"FeePeriodClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"sUSDAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snxRewards","type":"uint256"}],"name":"FeesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxyAddress","type":"address"}],"name":"ProxyUpdated","type":"event"},{"constant":true,"inputs":[],"name":"CONTRACT_NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FEE_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FEE_PERIOD_LENGTH","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"allNetworksDebtSharesSupply","outputs":[{"internalType":"uint256","name":"sharesSupply","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allNetworksSnxBackedDebt","outputs":[{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimFees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"claimingForAddress","type":"address"}],"name":"claimOnBehalf","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"closeCurrentFeePeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"allNetworksSnxBackedDebt","type":"uint256"},{"internalType":"uint256","name":"allNetworksDebtSharesSupply","type":"uint256"}],"name":"closeSecondary","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"period","type":"uint256"}],"name":"effectiveDebtRatioForPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feePeriodDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"feesAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"feesBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"feesByPeriod","outputs":[{"internalType":"uint256[2][2]","name":"results","type":"uint256[2][2]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"feesToBurn","outputs":[{"internalType":"uint256","name":"feesFromPeriod","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_claimingAddress","type":"address"}],"name":"getLastFeeWithdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getPenaltyThresholdRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"feePeriodIndex","type":"uint256"},{"internalType":"uint256","name":"feePeriodId","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"feesToDistribute","type":"uint256"},{"internalType":"uint256","name":"feesClaimed","type":"uint256"},{"internalType":"uint256","name":"rewardsToDistribute","type":"uint256"},{"internalType":"uint256","name":"rewardsClaimed","type":"uint256"}],"name":"importFeePeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isFeesClaimable","outputs":[{"internalType":"bool","name":"feesClaimable","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"issuanceRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"messageSender","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proxy","outputs":[{"internalType":"contract Proxy","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"recentFeePeriods","outputs":[{"internalType":"uint64","name":"feePeriodId","type":"uint64"},{"internalType":"uint64","name":"unused","type":"uint64"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint256","name":"feesToDistribute","type":"uint256"},{"internalType":"uint256","name":"feesClaimed","type":"uint256"},{"internalType":"uint256","name":"rewardsToDistribute","type":"uint256"},{"internalType":"uint256","name":"rewardsClaimed","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recordFeePaid","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"setMessageSender","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_proxy","type":"address"}],"name":"setProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setRewardsToDistribute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"setupExpiryTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"targetThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalFeesAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalFeesBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalRewardsAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]

6080604052631cd554d160e21b6007553480156200001c57600080fd5b506040516200456d3803806200456d8339810160408190526200003f9162000226565b8080621baf8085856001600160a01b038116620000795760405162461bcd60e51b8152600401620000709062000348565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91620000c691849062000310565b60405180910390a1506000546001600160a01b0316620000fa5760405162461bcd60e51b8152600401620000709062000336565b600280546001600160a01b0319166001600160a01b0383161790556040517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e906200014790839062000300565b60405180910390a1504201600455600580546001600160a01b0319166001600160a01b0392909216919091179055506001620001846000620001e7565b80546001600160401b0319166001600160401b039290921691909117905542620001af6000620001e7565b80546001600160401b03929092166801000000000000000002600160401b600160801b031990921691909117905550620003a3915050565b60006008600260ff16836016540181620001fd57fe5b06600281106200020957fe5b6007020192915050565b8051620002208162000389565b92915050565b6000806000606084860312156200023c57600080fd5b60006200024a868662000213565b93505060206200025d8682870162000213565b9250506040620002708682870162000213565b9150509250925092565b620002858162000375565b82525050565b620002858162000363565b6000620002a56011836200035a565b7013dddb995c881b5d5cdd081899481cd95d607a1b815260200192915050565b6000620002d46019836200035a565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b602081016200022082846200027a565b604081016200032082856200027a565b6200032f60208301846200028b565b9392505050565b60208082528101620002208162000296565b602080825281016200022081620002c5565b90815260200190565b60006001600160a01b03821662000220565b600062000220826000620002208262000363565b620003948162000363565b8114620003a057600080fd5b50565b6141ba80620003b36000396000f3fe608060405234801561001057600080fd5b50600436106102c85760003560e01c80636de813f11161017b578063b410a034116100d8578063e0e6393d1161008c578063ec55688911610071578063ec55688914610516578063f43d41611461051e578063fd1f498d14610531576102c8565b8063e0e6393d14610506578063eb1edd611461050e576102c8565b8063cff2ddad116100bd578063cff2ddad146104e1578063d294f093146104f6578063d67bdd25146104fe576102c8565b8063b410a034146104c6578063bc67f832146104ce576102c8565b8063899ffef41161012f57806397107d6d1161011457806397107d6d14610498578063a419b69a146104ab578063ac834193146104be576102c8565b8063899ffef41461047b5780638da5cb5b14610490576102c8565b806373941b961161016057806373941b9614610458578063741853601461046b57806379ba509714610473576102c8565b80636de813f11461044857806372ccd69e14610450576102c8565b80633ebc457a11610229578063569249d0116101dd578063614d08f8116101c2578063614d08f81461041a578063642fbd8b146104225780636466f45e14610435576102c8565b8063569249d0146103ff57806359a2f19f14610407576102c8565b806341c178c31161020e57806341c178c3146103da57806346ba2d90146103e257806353a47bb7146103ea576102c8565b80633ebc457a146103ac5780633fcd2240146103b4576102c8565b806322425fa4116102805780632af64bd3116102655780632af64bd31461036f5780632e227eeb14610384578063331400161461038c576102c8565b806322425fa41461035457806322bf55ef1461035c576102c8565b80630813071c116102b15780630813071c1461030b5780630de586151461031e5780631627540c1461033f576102c8565b806304f3bcec146102cd57806307ea50cd146102eb575b600080fd5b6102d5610544565b6040516102e29190613e6a565b60405180910390f35b6102fe6102f936600461319a565b610553565b6040516102e29190613d87565b6102fe6103193660046131de565b610628565b61033161032c36600461319a565b61073a565b6040516102e2929190613dbe565b61035261034d36600461319a565b6107bc565b005b6102fe61081a565b61035261036a366004613254565b61082a565b610377610887565b6040516102e29190613d79565b61033161099e565b61039f61039a36600461319a565b610b25565b6040516102e29190613d5a565b610352610d1c565b6103c76103c2366004613254565b610f24565b6040516102e29796959493929190613fe7565b610331610fd2565b6102fe611080565b6103f2611086565b6040516102e29190613ce0565b6102fe611095565b61037761041536600461319a565b6110f0565b6102fe611102565b6102fe61043036600461319a565b611126565b61037761044336600461319a565b6111c7565b6102fe6112f3565b6102fe611348565b6103526104663660046132a2565b61135d565b610352611445565b610352611597565b610483611633565b6040516102e29190613d68565b6103f261198d565b6103526104a636600461319a565b61199c565b6102fe6104b936600461319a565b6119ef565b6102fe611a0e565b6102fe611aba565b6103526104dc36600461319a565b611ac4565b6104e9611aee565b6040516102e2919061404f565b610377611af3565b6103f2611b6a565b6102fe611b79565b6103f2611b83565b6102d5611b9b565b61035261052c3660046132c1565b611baa565b61035261053f366004613254565b611d5a565b6005546001600160a01b031681565b600061055d611dc6565b6001600160a01b031663bdc963d87f6c6173745f6665655f7769746864726177616c000000000000000000000000008460405160200161059e929190613c79565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016105d09190613d87565b60206040518083038186803b1580156105e857600080fd5b505afa1580156105fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106209190810190613236565b90505b919050565b6000811580610638575060028210155b1561064557506000610734565b61065160018303611df1565b5468010000000000000000900467ffffffffffffffff1661067457506000610734565b61067c611e1b565b6001600160a01b0316638ced14df846008856002811061069857fe5b60070201546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526106e1929167ffffffffffffffff1690600401613d17565b60206040518083038186803b1580156106f957600080fd5b505afa15801561070d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506107319190810190613236565b90505b92915050565b6000806107456130b4565b61074e84610b25565b905060008060015b60028110156107af5761077b84826002811061076e57fe5b6020020151518490611e46565b92506107a584826002811061078c57fe5b602002015160016020020151839063ffffffff611e4616565b9150600101610756565b509093509150505b915091565b6107c4611e6b565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229061080f908390613ce0565b60405180910390a150565b6000610824611e97565b90505b90565b61083333611f5e565b6108585760405162461bcd60e51b815260040161084f90613e89565b60405180910390fd5b610876816108666000611df1565b600301549063ffffffff611e4616565b6108806000611df1565b6003015550565b60006060610893611633565b905060005b81518110156109955760008282815181106108af57fe5b602090810291909101810151600081815260069092526040918290205460055492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a72190610900908590600401613d87565b60206040518083038186803b15801561091857600080fd5b505afa15801561092c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061095091908101906131c0565b6001600160a01b031614158061097b57506000818152600660205260409020546001600160a01b0316155b1561098c5760009350505050610827565b50600101610898565b50600191505090565b6000806000806109cd7f6578743a41676772656761746f7249737375656453796e746873000000000000612102565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015610a0557600080fd5b505afa158015610a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a3d919081019061335d565b50935050925050600080610a707f6578743a41676772656761746f7244656274526174696f000000000000000000612102565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015610aa857600080fd5b505afa158015610abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ae0919081019061335d565b50919450909250859150508215610b0657610b01818463ffffffff61215f16565b610b09565b60005b9650818410610b185781610b1a565b835b955050505050509091565b610b2d6130b4565b600080610b38611e1b565b6040517fe6d24bbd0000000000000000000000000000000000000000000000000000000081529091506001600160a01b0382169063e6d24bbd90610b80908790600401613ce0565b60206040518083038186803b158015610b9857600080fd5b505afa158015610bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bd09190810190613236565b9150600080610be0600085612178565b8651829052865160200181905290925090506000610bfd87610553565b905060015b8015610d11576000610c1382611df1565b5467ffffffffffffffff16905080831015610d07576040517f8ced14df0000000000000000000000000000000000000000000000000000000081526001600160a01b03871690638ced14df90610c79908c9067ffffffffffffffff861690600401613d17565b60206040518083038186803b158015610c9157600080fd5b505afa158015610ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cc99190810190613236565b9650610cd58288612178565b909550935084888360028110610ce757fe5b60200201515283888360028110610cfa57fe5b6020020151600160200201525b5060001901610c02565b505050505050919050565b610d246121dc565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015610d5c57600080fd5b505afa158015610d70573d6000803e3d6000fd5b505050506000610d7e611e97565b11610d9b5760405162461bcd60e51b815260040161084f90613fc9565b610da3611e97565b4203610daf6000611df1565b5468010000000000000000900467ffffffffffffffff161115610de45760405162461bcd60e51b815260040161084f90613ea9565b6000610dee610fd2565b5090506000610dfb61099e565b509050610e088282612207565b6005546040517fdacb2d010000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063dacb2d0190610e71907f53796e746865746978427269646765546f4f7074696d69736d0000000000000090600401613dec565b60206040518083038186803b158015610e8957600080fd5b505afa158015610e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ec191908101906131c0565b6001600160a01b031663b9958ab883836040518363ffffffff1660e01b8152600401610eee929190613dbe565b600060405180830381600087803b158015610f0857600080fd5b505af1158015610f1c573d6000803e3d6000fd5b505050505050565b6000806000806000806000610f376130e1565b610f4089611df1565b6040805161010081018252825467ffffffffffffffff80821680845268010000000000000000909204166020830181905260018501549383019390935260028401546060830152600384015460808301819052600485015460a08401819052600586015460c0850181905260069096015460e0909401849052919e60009e50939c509a50985091965090945092505050565b6000806000806110017f6578743a41676772656761746f7249737375656453796e746873000000000000612102565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561103957600080fd5b505afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611071919081019061335d565b50919791965090945050505050565b60045481565b6001546001600160a01b031681565b60008060015b60028110156110ea576110c16110b082611df1565b60030154839063ffffffff611e4616565b91506110e06110cf82611df1565b60040154839063ffffffff6125cd16565b915060010161109b565b50905090565b60006110fb826125f5565b5092915050565b7f466565506f6f6c0000000000000000000000000000000000000000000000000081565b600080611131611e1b565b90506000816001600160a01b031663e6d24bbd856040518263ffffffff1660e01b81526004016111619190613ce0565b60206040518083038186803b15801561117957600080fd5b505afa15801561118d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111b19190810190613236565b90506111be600082612178565b50949350505050565b60006111d16121dc565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561120957600080fd5b505afa15801561121d573d6000803e3d6000fd5b505050506112296126e9565b611231612728565b6003546040517f21f4ae570000000000000000000000000000000000000000000000000000000081526001600160a01b03928316926321f4ae579261127e92879290911690600401613cfc565b60206040518083038186803b15801561129657600080fd5b505afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112ce9190810190613218565b6112ea5760405162461bcd60e51b815260040161084f90613f39565b61062082612753565b60008060015b60028110156110ea5761131f61130e82611df1565b60050154839063ffffffff611e4616565b915061133e61132d82611df1565b60060154839063ffffffff6125cd16565b91506001016112f9565b60006113546001611df1565b60040154905090565b3330148061141b57506005546040516321f8a72160e01b81526001600160a01b03909116906321f8a721906113b6907f53796e746865746978427269646765546f42617365000000000000000000000090600401613d87565b60206040518083038186803b1580156113ce57600080fd5b505afa1580156113e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061140691908101906131c0565b6001600160a01b0316336001600160a01b0316145b6114375760405162461bcd60e51b815260040161084f90613f79565b6114418282612207565b5050565b606061144f611633565b905060005b815181101561144157600082828151811061146b57fe5b602002602001015190506000600560009054906101000a90046001600160a01b03166001600160a01b031663dacb2d0183846040516020016114ad9190613cca565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016114d9929190613dcc565b60206040518083038186803b1580156114f157600080fd5b505afa158015611505573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061152991908101906131c0565b6000838152600660205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68906115859084908490613d95565b60405180910390a15050600101611454565b6001546001600160a01b031633146115c15760405162461bcd60e51b815260040161084f90613e99565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c92611604926001600160a01b0391821692911690613cfc565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60608061163e612833565b60408051600e8082526101e0820190925291925060609190602082016101c0803883390190505090507f53797374656d53746174757300000000000000000000000000000000000000008160008151811061169557fe5b6020026020010181815250507f53796e7468657469784465627453686172650000000000000000000000000000816001815181106116cf57fe5b6020026020010181815250507f466565506f6f6c457465726e616c53746f7261676500000000000000000000008160028151811061170957fe5b6020026020010181815250507f45786368616e67657200000000000000000000000000000000000000000000008160038151811061174357fe5b6020026020010181815250506524b9b9bab2b960d11b8160048151811061176657fe5b6020026020010181815250507f526577617264457363726f775632000000000000000000000000000000000000816005815181106117a057fe5b6020026020010181815250507f44656c6567617465417070726f76616c73000000000000000000000000000000816006815181106117da57fe5b6020026020010181815250507f52657761726473446973747269627574696f6e000000000000000000000000008160078151811061181457fe5b6020026020010181815250507f436f6c6c61746572616c4d616e616765720000000000000000000000000000008160088151811061184e57fe5b6020026020010181815250507f57726170706572466163746f72790000000000000000000000000000000000008160098151811061188857fe5b6020026020010181815250507f457468657257726170706572000000000000000000000000000000000000000081600a815181106118c257fe5b6020026020010181815250507f6578743a41676772656761746f7249737375656453796e74687300000000000081600b815181106118fc57fe5b6020026020010181815250507f6578743a41676772656761746f7244656274526174696f00000000000000000081600c8151811061193657fe5b6020026020010181815250507f467574757265734d61726b65744d616e6167657200000000000000000000000081600d8151811061197057fe5b6020026020010181815250506119868282612892565b9250505090565b6000546001600160a01b031681565b6119a4611e6b565b600280546001600160a01b0319166001600160a01b0383161790556040517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9061080f908390613cee565b60006119f96130b4565b611a0283610b25565b60200151519392505050565b6000610824611aa6611a1e612947565b732ad7ccaac0eeb396c3a5fc2b73a885435688c0d563907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611a6257600080fd5b505af4158015611a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a9a9190810190613236565b9063ffffffff611e4616565b611aae6129be565b9063ffffffff612a3516565b60006108246129be565b611acc612a5f565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b600281565b6000611afd6121dc565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015611b3557600080fd5b505afa158015611b49573d6000803e3d6000fd5b50505050611b556126e9565b600354610824906001600160a01b0316612753565b6003546001600160a01b031681565b6000610824612947565b73feefeefeefeefeefeefeefeefeefeefeefeefeef81565b6002546001600160a01b031681565b611bb2612a89565b6004544210611bd35760405162461bcd60e51b815260040161084f90613f89565b60028710611bf35760405162461bcd60e51b815260040161084f90613fa9565b6040518061010001604052808767ffffffffffffffff1681526020018667ffffffffffffffff16815260200160008152602001600081526020018581526020018481526020018381526020018281525060088860028110611c5057fe5b8251600791909102919091018054602084015167ffffffffffffffff90811668010000000000000000026fffffffffffffffff0000000000000000199190941667ffffffffffffffff19909216919091171691909117815560408201516001820155606082015160028201556080820151600382015560a0820151600482015560c0820151600582015560e09091015160069091015586611d5157611cf3612af7565b6001600160a01b03166331e6da5a876040518263ffffffff1660e01b8152600401611d1e9190613fd9565b600060405180830381600087803b158015611d3857600080fd5b505af1158015611d4c573d6000803e3d6000fd5b505050505b50505050505050565b611d626126e9565b611d6a612b0b565b6003546001600160a01b03908116911614611d975760405162461bcd60e51b815260040161084f90613f09565b611db581611da56000611df1565b600501549063ffffffff611e4616565b611dbf6000611df1565b6005015550565b60006108247f466565506f6f6c457465726e616c53746f726167650000000000000000000000612102565b60006008600260ff16836016540181611e0657fe5b0660028110611e1157fe5b6007020192915050565b60006108247f53796e7468657469784465627453686172650000000000000000000000000000612102565b6000828201838110156107315760405162461bcd60e51b815260040161084f90613ec9565b6000546001600160a01b03163314611e955760405162461bcd60e51b815260040161084f90613f49565b565b6000611ea1612b36565b6001600160a01b03166323257c2b7f53797374656d53657474696e67730000000000000000000000000000000000007f666565506572696f644475726174696f6e0000000000000000000000000000006040518363ffffffff1660e01b8152600401611f0e929190613dbe565b60206040518083038186803b158015611f2657600080fd5b505afa158015611f3a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108249190810190613236565b6000611f68612b61565b6001600160a01b0316826001600160a01b0316148061200a57506000611f8c612af7565b6001600160a01b03166316b2213f846040518263ffffffff1660e01b8152600401611fb79190613ce0565b60206040518083038186803b158015611fcf57600080fd5b505afa158015611fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120079190810190613236565b14155b806120935750612018612b8c565b6001600160a01b031663b38988f7836040518263ffffffff1660e01b81526004016120439190613ce0565b60206040518083038186803b15801561205b57600080fd5b505afa15801561206f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120939190810190613218565b806120b657506120a1612bb7565b6001600160a01b0316826001600160a01b0316145b806120d957506120c4612be2565b6001600160a01b0316826001600160a01b0316145b8061062057506120e7612c0d565b6001600160a01b0316826001600160a01b0316149050919050565b60008181526006602090815260408083205490516001600160a01b03909116918215159161213291869101613caa565b604051602081830303815290604052906110fb5760405162461bcd60e51b815260040161084f9190613e78565b600061073183836b033b2e3c9fd0803ce8000000612c38565b6000808261218b575060009050806121d5565b600061219685611df1565b905060006121b1858360030154612a3590919063ffffffff16565b905060006121cc868460050154612a3590919063ffffffff16565b91945090925050505b9250929050565b60006108247f53797374656d5374617475730000000000000000000000000000000000000000612102565b61220f612c0d565b6001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561224957600080fd5b505af115801561225d573d6000803e3d6000fd5b50505050612269612be2565b6001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156122a357600080fd5b505af11580156122b7573d6000803e3d6000fd5b50505050806122c66000611df1565b60020155816122d56000611df1565b6001015560006122e481611df1565b905060006122f26001611df1565b90506123178260030154611a9a836004015484600301546125cd90919063ffffffff16565b6123216000611df1565b6003015560058083015460068301549183015461234892611a9a919063ffffffff6125cd16565b6123526000611df1565b60050155600061236181611df1565b60030154111561243557612373612af7565b6001600160a01b031663c81ff8fa60075473feefeefeefeefeefeefeefeefeefeefeefeefeef6123a36000611df1565b600301546040518463ffffffff1660e01b81526004016123c593929190613da3565b602060405180830381600087803b1580156123df57600080fd5b505af11580156123f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124179190810190613218565b506124226000611df1565b600301546124306000611df1565b600401555b60165461246e9060029061246290600190612456908463ffffffff611e4616565b9063ffffffff6125cd16565b9063ffffffff612c7d16565b60168190556008906002811061248057fe5b6007020180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000168155600060018201819055600282018190556003820181905560048201819055600582018190556006909101819055429081906124e490611df1565b805467ffffffffffffffff191667ffffffffffffffff929092169190911790554261250f6000611df1565b805467ffffffffffffffff9290921668010000000000000000026fffffffffffffffff00000000000000001990921691909117905561254c612af7565b6001600160a01b03166331e6da5a826040518263ffffffff1660e01b81526004016125779190613fd9565b600060405180830381600087803b15801561259157600080fd5b505af11580156125a5573d6000803e3d6000fd5b505050506125c66125b66001611df1565b5467ffffffffffffffff16612cad565b5050505050565b6000828211156125ef5760405162461bcd60e51b815260040161084f90613ed9565b50900390565b600080600080612603612af7565b6001600160a01b031663ae3bbbbb866040518263ffffffff1660e01b815260040161262e9190613ce0565b604080518083038186803b15801561264557600080fd5b505afa158015612659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061267d9190810190613272565b91509150600061268b6129be565b9050808310156126a357506001935091506107b79050565b60006126c06126b3611a1e612947565b839063ffffffff612a3516565b9050808411156126da5760008395509550505050506107b7565b50600194509092505050915091565b6002546001600160a01b0316331480159061270f57506003546001600160a01b03163314155b15611e9557600380546001600160a01b03191633179055565b60006108247f44656c6567617465417070726f76616c73000000000000000000000000000000612102565b6000808080808080612764886125f5565b91509150816127855760405162461bcd60e51b815260040161084f90613f59565b80156127a35760405162461bcd60e51b815260040161084f90613f19565b6127ac8861073a565b9094509250831515806127bf5750600083115b6127db5760405162461bcd60e51b815260040161084f90613ef9565b6127f9886127e96001611df1565b5467ffffffffffffffff16612d65565b839450600083111561281a5761280e83612de2565b955061281a8887612eac565b612825888688612f5e565b506001979650505050505050565b604080516001808252818301909252606091602080830190803883390190505090507f466c657869626c6553746f7261676500000000000000000000000000000000008160008151811061288357fe5b60200260200101818152505090565b606081518351016040519080825280602002602001820160405280156128c2578160200160208202803883390190505b50905060005b8351811015612904578381815181106128dd57fe5b60200260200101518282815181106128f157fe5b60209081029190910101526001016128c8565b5060005b82518110156110fb5782818151811061291d57fe5b602002602001015182828651018151811061293457fe5b6020908102919091010152600101612908565b6000612951612b36565b6001600160a01b03166323257c2b7f53797374656d53657474696e67730000000000000000000000000000000000007f7461726765745468726573686f6c6400000000000000000000000000000000006040518363ffffffff1660e01b8152600401611f0e929190613dbe565b60006129c8612b36565b6001600160a01b03166323257c2b7f53797374656d53657474696e67730000000000000000000000000000000000007f69737375616e6365526174696f000000000000000000000000000000000000006040518363ffffffff1660e01b8152600401611f0e929190613dbe565b6000670de0b6b3a7640000612a50848463ffffffff61301a16565b81612a5757fe5b049392505050565b6002546001600160a01b03163314611e955760405162461bcd60e51b815260040161084f90613fb9565b6002546001600160a01b03163314801590612aaf57506003546001600160a01b03163314155b15612ac757600380546001600160a01b031916331790555b6000546003546001600160a01b03908116911614611e955760405162461bcd60e51b815260040161084f90613eb9565b60006108246524b9b9bab2b960d11b612102565b60006108247f52657761726473446973747269627574696f6e00000000000000000000000000612102565b60006108247f466c657869626c6553746f726167650000000000000000000000000000000000612102565b60006108247f45786368616e6765720000000000000000000000000000000000000000000000612102565b60006108247f436f6c6c61746572616c4d616e61676572000000000000000000000000000000612102565b60006108247f467574757265734d61726b65744d616e61676572000000000000000000000000612102565b60006108247f57726170706572466163746f7279000000000000000000000000000000000000612102565b60006108247f4574686572577261707065720000000000000000000000000000000000000000612102565b600080612c5e84612c5287600a870263ffffffff61301a16565b9063ffffffff61305416565b90506005600a820610612c6f57600a015b600a900490505b9392505050565b600081612c9c5760405162461bcd60e51b815260040161084f90613f29565b818381612ca557fe5b069392505050565b6002546040516001600160a01b039091169063907dff9790612cd3908490602001613d87565b6040516020818303038152906040526001604051612cf090613cd5565b6040519081900381207fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168252612d3793929160009081908190600401613e0b565b600060405180830381600087803b158015612d5157600080fd5b505af11580156125c6573d6000803e3d6000fd5b612d6d611dc6565b6001600160a01b0316633562fd207f6c6173745f6665655f7769746864726177616c0000000000000000000000000084604051602001612dae929190613c79565b60405160208183030381529060405280519060200120836040518363ffffffff1660e01b8152600401610eee929190613dbe565b6000818160015b6002811015612ea4576000612e1d612e0083611df1565b60060154612e0d84611df1565b600501549063ffffffff6125cd16565b90508015612e9a576000848210612e345784612e36565b815b9050612e5581612e4585611df1565b600601549063ffffffff611e4616565b612e5e84611df1565b60060155612e72858263ffffffff6125cd16565b9450612e84848263ffffffff611e4616565b935084612e98578395505050505050610623565b505b5060001901612de9565b509392505050565b816001600160a01b03811673feefeefeefeefeefeefeefeefeefeefeefeefeef1415612eea5760405162461bcd60e51b815260040161084f90613f99565b6301dfe200612ef7613089565b6001600160a01b0316631bb47b448585846040518463ffffffff1660e01b8152600401612f2693929190613d32565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b5050505050505050565b6002546040516001600160a01b039091169063907dff9790612f8890869086908690602001613d32565b6040516020818303038152906040526001604051612fa590613c9f565b6040519081900381207fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168252612fec93929160009081908190600401613e0b565b600060405180830381600087803b15801561300657600080fd5b505af1158015611d51573d6000803e3d6000fd5b60008261302957506000610734565b8282028284828161303657fe5b04146107315760405162461bcd60e51b815260040161084f90613f69565b60008082116130755760405162461bcd60e51b815260040161084f90613ee9565b600082848161308057fe5b04949350505050565b60006108247f526577617264457363726f775632000000000000000000000000000000000000612102565b60405180604001604052806002905b6130cb61313a565b8152602001906001900390816130c35790505090565b604051806101000160405280600067ffffffffffffffff168152602001600067ffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180604001604052806002906020820280388339509192915050565b803561073481614145565b805161073481614145565b80516107348161415c565b805161073481614165565b803561073481614165565b80516107348161416e565b6000602082840312156131ac57600080fd5b60006131b88484613158565b949350505050565b6000602082840312156131d257600080fd5b60006131b88484613163565b600080604083850312156131f157600080fd5b60006131fd8585613158565b925050602061320e85828601613184565b9150509250929050565b60006020828403121561322a57600080fd5b60006131b8848461316e565b60006020828403121561324857600080fd5b60006131b88484613179565b60006020828403121561326657600080fd5b60006131b88484613184565b6000806040838503121561328557600080fd5b60006132918585613179565b925050602061320e8582860161316e565b600080604083850312156132b557600080fd5b60006131fd8585613184565b600080600080600080600060e0888a0312156132dc57600080fd5b60006132e88a8a613184565b97505060206132f98a828b01613184565b965050604061330a8a828b01613184565b955050606061331b8a828b01613184565b945050608061332c8a828b01613184565b93505060a061333d8a828b01613184565b92505060c061334e8a828b01613184565b91505092959891949750929550565b600080600080600060a0868803121561337557600080fd5b6000613381888861318f565b955050602061339288828901613179565b94505060406133a388828901613179565b93505060606133b488828901613179565b92505060806133c58882890161318f565b9150509295509295909350565b60006133de83836134c8565b505060400190565b60006133f2838361351d565b505060200190565b613403816140c9565b82525050565b61340381614076565b61340361341e82614076565b614124565b61342c81614063565b6134368184610623565b925061344182610827565b8060005b83811015610f1c57815161345987826133d2565b96506134648361405d565b925050600101613445565b600061347a82614069565b613484818561406d565b935061348f8361405d565b8060005b838110156134bd5781516134a788826133e6565b97506134b28361405d565b925050600101613493565b509495945050505050565b6134d181614063565b6134db8184610623565b92506134e682610827565b8060005b83811015610f1c5781516134fe87826133e6565b96506135098361405d565b9250506001016134ea565b61340381614081565b61340381610827565b61340361353282610827565b610827565b600061354282614069565b61354c818561406d565b935061355c8185602086016140f4565b61356581614135565b9093019392505050565b613403816140d0565b613403816140db565b613403816140e9565b600061359760178361406d565b7f4f6e6c7920496e7465726e616c20436f6e747261637473000000000000000000815260200192915050565b60006135d060358361406d565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527f2063616e20616363657074206f776e6572736869700000000000000000000000602082015260400192915050565b600061362f601d8361406d565b7f546f6f206561726c7920746f20636c6f73652066656520706572696f64000000815260200192915050565b600061366860138361406d565b7f4f776e6572206f6e6c792066756e6374696f6e00000000000000000000000000815260200192915050565b60006136a1602483610623565b7f46656573436c61696d656428616464726573732c75696e743235362c75696e7481527f3235362900000000000000000000000000000000000000000000000000000000602082015260240192915050565b6000613700601b8361406d565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613739601e8361406d565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000613772601a8361406d565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b60006137ab60408361406d565b7f4e6f2066656573206f72207265776172647320617661696c61626c6520666f7281527f20706572696f642c206f72206665657320616c726561647920636c61696d6564602082015260400192915050565b600061380a602b8361406d565b7f4d697373696e6720636f6e74726163743a2053796e746865746978427269646781527f65546f4f7074696d69736d000000000000000000000000000000000000000000602082015260400192915050565b6000613869601183610623565b7f4d697373696e6720616464726573733a20000000000000000000000000000000815260110192915050565b60006138a260188361406d565b7f52657761726473446973747269627574696f6e206f6e6c790000000000000000815260200192915050565b60006138db601e8361406d565b7f412073796e7468206f7220534e58207261746520697320696e76616c69640000815260200192915050565b600061391460188361406d565b7f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815260200192915050565b600061394d601f8361406d565b7f4e6f7420617070726f76656420746f20636c61696d206f6e20626568616c6600815260200192915050565b6000613986602f8361406d565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681527f6f726d207468697320616374696f6e0000000000000000000000000000000000602082015260400192915050565b60006139e5601f8361406d565b7f432d526174696f2062656c6f772070656e616c7479207468726573686f6c6400815260200192915050565b6000613a1e60218361406d565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f81527f7700000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613a7d601b8361406d565b7f4f6e6c792076616c69642072656c617965722063616e2063616c6c0000000000815260200192915050565b6000613ab660298361406d565b7f43616e206f6e6c7920706572666f726d207468697320616374696f6e2064757281527f696e672073657475700000000000000000000000000000000000000000000000602082015260400192915050565b6000613b15601983610623565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000613b4e60178361406d565b7f4665652061646472657373206e6f7420616c6c6f776564000000000000000000815260200192915050565b6000613b8760188361406d565b7f696e76616c69642066656520706572696f6420696e6465780000000000000000815260200192915050565b6000613bc0601883610623565b7f466565506572696f64436c6f7365642875696e74323536290000000000000000815260180192915050565b6000613bf960178361406d565b7f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000815260200192915050565b6000613c32601b8361406d565b7f46656520506572696f64204475726174696f6e206e6f74207365740000000000815260200192915050565b61340381614086565b613403816140a7565b613403816140b4565b6000613c858285613526565b602082019150613c958284613412565b5060140192915050565b600061073482613694565b6000613cb58261385c565b9150613cc18284613526565b50602001919050565b6000613cb582613b08565b600061073482613bb3565b602081016107348284613409565b6020810161073482846133fa565b60408101613d0a8285613409565b612c766020830184613409565b60408101613d258285613409565b612c76602083018461351d565b60608101613d408286613409565b613d4d602083018561351d565b6131b8604083018461351d565b608081016107348284613423565b60208082528101610731818461346f565b602081016107348284613514565b60208101610734828461351d565b60408101613d0a828561351d565b60608101613db1828661351d565b613d4d6020830185613409565b60408101613d25828561351d565b60408101613dda828561351d565b81810360208301526131b88184613537565b60408101613dfa828461351d565b8181036020830152610731816137fd565b60c08082528101613e1c8189613537565b9050613e2b6020830188613581565b613e38604083018761351d565b613e456060830186613578565b613e526080830185613578565b613e5f60a0830184613578565b979650505050505050565b60208101610734828461356f565b602080825281016107318184613537565b602080825281016106208161358a565b60208082528101610620816135c3565b6020808252810161062081613622565b602080825281016106208161365b565b60208082528101610620816136f3565b602080825281016106208161372c565b6020808252810161062081613765565b602080825281016106208161379e565b6020808252810161062081613895565b60208082528101610620816138ce565b6020808252810161062081613907565b6020808252810161062081613940565b6020808252810161062081613979565b60208082528101610620816139d8565b6020808252810161062081613a11565b6020808252810161062081613a70565b6020808252810161062081613aa9565b6020808252810161062081613b41565b6020808252810161062081613b7a565b6020808252810161062081613bec565b6020808252810161062081613c25565b602081016107348284613c5e565b60e08101613ff5828a613c67565b6140026020830189613c67565b61400f6040830188613c67565b61401c606083018761351d565b614029608083018661351d565b61403660a083018561351d565b61404360c083018461351d565b98975050505050505050565b602081016107348284613c70565b60200190565b50600290565b5190565b90815260200190565b60006106208261409b565b151590565b6fffffffffffffffffffffffffffffffff1690565b6001600160a01b031690565b67ffffffffffffffff1690565b60ff1690565b69ffffffffffffffffffff1690565b6000610620825b600061062082614076565b600061062061353283610827565b600061062082610827565b60005b8381101561410f5781810151838201526020016140f7565b8381111561411e576000848401525b50505050565b60006106208260006106208261413f565b601f01601f191690565b60601b90565b61414e81614076565b811461415957600080fd5b50565b61414e81614081565b61414e81610827565b61414e816140ba56fea365627a7a7231582084a26b19e4e7aa56460b87d9fffabf4826221553c03ca462841e08c17a2953176c6578706572696d656e74616cf564736f6c6343000510004000000000000000000000000038fc5d5a5402cde8cb384c939d201522f087322900000000000000000000000048914229dedd5a9922f44441ffccfc2cb7856ee9000000000000000000000000529c553ef2d0370279dc8abf19702b98b166d252

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102c85760003560e01c80636de813f11161017b578063b410a034116100d8578063e0e6393d1161008c578063ec55688911610071578063ec55688914610516578063f43d41611461051e578063fd1f498d14610531576102c8565b8063e0e6393d14610506578063eb1edd611461050e576102c8565b8063cff2ddad116100bd578063cff2ddad146104e1578063d294f093146104f6578063d67bdd25146104fe576102c8565b8063b410a034146104c6578063bc67f832146104ce576102c8565b8063899ffef41161012f57806397107d6d1161011457806397107d6d14610498578063a419b69a146104ab578063ac834193146104be576102c8565b8063899ffef41461047b5780638da5cb5b14610490576102c8565b806373941b961161016057806373941b9614610458578063741853601461046b57806379ba509714610473576102c8565b80636de813f11461044857806372ccd69e14610450576102c8565b80633ebc457a11610229578063569249d0116101dd578063614d08f8116101c2578063614d08f81461041a578063642fbd8b146104225780636466f45e14610435576102c8565b8063569249d0146103ff57806359a2f19f14610407576102c8565b806341c178c31161020e57806341c178c3146103da57806346ba2d90146103e257806353a47bb7146103ea576102c8565b80633ebc457a146103ac5780633fcd2240146103b4576102c8565b806322425fa4116102805780632af64bd3116102655780632af64bd31461036f5780632e227eeb14610384578063331400161461038c576102c8565b806322425fa41461035457806322bf55ef1461035c576102c8565b80630813071c116102b15780630813071c1461030b5780630de586151461031e5780631627540c1461033f576102c8565b806304f3bcec146102cd57806307ea50cd146102eb575b600080fd5b6102d5610544565b6040516102e29190613e6a565b60405180910390f35b6102fe6102f936600461319a565b610553565b6040516102e29190613d87565b6102fe6103193660046131de565b610628565b61033161032c36600461319a565b61073a565b6040516102e2929190613dbe565b61035261034d36600461319a565b6107bc565b005b6102fe61081a565b61035261036a366004613254565b61082a565b610377610887565b6040516102e29190613d79565b61033161099e565b61039f61039a36600461319a565b610b25565b6040516102e29190613d5a565b610352610d1c565b6103c76103c2366004613254565b610f24565b6040516102e29796959493929190613fe7565b610331610fd2565b6102fe611080565b6103f2611086565b6040516102e29190613ce0565b6102fe611095565b61037761041536600461319a565b6110f0565b6102fe611102565b6102fe61043036600461319a565b611126565b61037761044336600461319a565b6111c7565b6102fe6112f3565b6102fe611348565b6103526104663660046132a2565b61135d565b610352611445565b610352611597565b610483611633565b6040516102e29190613d68565b6103f261198d565b6103526104a636600461319a565b61199c565b6102fe6104b936600461319a565b6119ef565b6102fe611a0e565b6102fe611aba565b6103526104dc36600461319a565b611ac4565b6104e9611aee565b6040516102e2919061404f565b610377611af3565b6103f2611b6a565b6102fe611b79565b6103f2611b83565b6102d5611b9b565b61035261052c3660046132c1565b611baa565b61035261053f366004613254565b611d5a565b6005546001600160a01b031681565b600061055d611dc6565b6001600160a01b031663bdc963d87f6c6173745f6665655f7769746864726177616c000000000000000000000000008460405160200161059e929190613c79565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016105d09190613d87565b60206040518083038186803b1580156105e857600080fd5b505afa1580156105fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106209190810190613236565b90505b919050565b6000811580610638575060028210155b1561064557506000610734565b61065160018303611df1565b5468010000000000000000900467ffffffffffffffff1661067457506000610734565b61067c611e1b565b6001600160a01b0316638ced14df846008856002811061069857fe5b60070201546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526106e1929167ffffffffffffffff1690600401613d17565b60206040518083038186803b1580156106f957600080fd5b505afa15801561070d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506107319190810190613236565b90505b92915050565b6000806107456130b4565b61074e84610b25565b905060008060015b60028110156107af5761077b84826002811061076e57fe5b6020020151518490611e46565b92506107a584826002811061078c57fe5b602002015160016020020151839063ffffffff611e4616565b9150600101610756565b509093509150505b915091565b6107c4611e6b565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229061080f908390613ce0565b60405180910390a150565b6000610824611e97565b90505b90565b61083333611f5e565b6108585760405162461bcd60e51b815260040161084f90613e89565b60405180910390fd5b610876816108666000611df1565b600301549063ffffffff611e4616565b6108806000611df1565b6003015550565b60006060610893611633565b905060005b81518110156109955760008282815181106108af57fe5b602090810291909101810151600081815260069092526040918290205460055492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a72190610900908590600401613d87565b60206040518083038186803b15801561091857600080fd5b505afa15801561092c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061095091908101906131c0565b6001600160a01b031614158061097b57506000818152600660205260409020546001600160a01b0316155b1561098c5760009350505050610827565b50600101610898565b50600191505090565b6000806000806109cd7f6578743a41676772656761746f7249737375656453796e746873000000000000612102565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015610a0557600080fd5b505afa158015610a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a3d919081019061335d565b50935050925050600080610a707f6578743a41676772656761746f7244656274526174696f000000000000000000612102565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015610aa857600080fd5b505afa158015610abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ae0919081019061335d565b50919450909250859150508215610b0657610b01818463ffffffff61215f16565b610b09565b60005b9650818410610b185781610b1a565b835b955050505050509091565b610b2d6130b4565b600080610b38611e1b565b6040517fe6d24bbd0000000000000000000000000000000000000000000000000000000081529091506001600160a01b0382169063e6d24bbd90610b80908790600401613ce0565b60206040518083038186803b158015610b9857600080fd5b505afa158015610bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bd09190810190613236565b9150600080610be0600085612178565b8651829052865160200181905290925090506000610bfd87610553565b905060015b8015610d11576000610c1382611df1565b5467ffffffffffffffff16905080831015610d07576040517f8ced14df0000000000000000000000000000000000000000000000000000000081526001600160a01b03871690638ced14df90610c79908c9067ffffffffffffffff861690600401613d17565b60206040518083038186803b158015610c9157600080fd5b505afa158015610ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cc99190810190613236565b9650610cd58288612178565b909550935084888360028110610ce757fe5b60200201515283888360028110610cfa57fe5b6020020151600160200201525b5060001901610c02565b505050505050919050565b610d246121dc565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015610d5c57600080fd5b505afa158015610d70573d6000803e3d6000fd5b505050506000610d7e611e97565b11610d9b5760405162461bcd60e51b815260040161084f90613fc9565b610da3611e97565b4203610daf6000611df1565b5468010000000000000000900467ffffffffffffffff161115610de45760405162461bcd60e51b815260040161084f90613ea9565b6000610dee610fd2565b5090506000610dfb61099e565b509050610e088282612207565b6005546040517fdacb2d010000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063dacb2d0190610e71907f53796e746865746978427269646765546f4f7074696d69736d0000000000000090600401613dec565b60206040518083038186803b158015610e8957600080fd5b505afa158015610e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ec191908101906131c0565b6001600160a01b031663b9958ab883836040518363ffffffff1660e01b8152600401610eee929190613dbe565b600060405180830381600087803b158015610f0857600080fd5b505af1158015610f1c573d6000803e3d6000fd5b505050505050565b6000806000806000806000610f376130e1565b610f4089611df1565b6040805161010081018252825467ffffffffffffffff80821680845268010000000000000000909204166020830181905260018501549383019390935260028401546060830152600384015460808301819052600485015460a08401819052600586015460c0850181905260069096015460e0909401849052919e60009e50939c509a50985091965090945092505050565b6000806000806110017f6578743a41676772656761746f7249737375656453796e746873000000000000612102565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561103957600080fd5b505afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611071919081019061335d565b50919791965090945050505050565b60045481565b6001546001600160a01b031681565b60008060015b60028110156110ea576110c16110b082611df1565b60030154839063ffffffff611e4616565b91506110e06110cf82611df1565b60040154839063ffffffff6125cd16565b915060010161109b565b50905090565b60006110fb826125f5565b5092915050565b7f466565506f6f6c0000000000000000000000000000000000000000000000000081565b600080611131611e1b565b90506000816001600160a01b031663e6d24bbd856040518263ffffffff1660e01b81526004016111619190613ce0565b60206040518083038186803b15801561117957600080fd5b505afa15801561118d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111b19190810190613236565b90506111be600082612178565b50949350505050565b60006111d16121dc565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561120957600080fd5b505afa15801561121d573d6000803e3d6000fd5b505050506112296126e9565b611231612728565b6003546040517f21f4ae570000000000000000000000000000000000000000000000000000000081526001600160a01b03928316926321f4ae579261127e92879290911690600401613cfc565b60206040518083038186803b15801561129657600080fd5b505afa1580156112aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112ce9190810190613218565b6112ea5760405162461bcd60e51b815260040161084f90613f39565b61062082612753565b60008060015b60028110156110ea5761131f61130e82611df1565b60050154839063ffffffff611e4616565b915061133e61132d82611df1565b60060154839063ffffffff6125cd16565b91506001016112f9565b60006113546001611df1565b60040154905090565b3330148061141b57506005546040516321f8a72160e01b81526001600160a01b03909116906321f8a721906113b6907f53796e746865746978427269646765546f42617365000000000000000000000090600401613d87565b60206040518083038186803b1580156113ce57600080fd5b505afa1580156113e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061140691908101906131c0565b6001600160a01b0316336001600160a01b0316145b6114375760405162461bcd60e51b815260040161084f90613f79565b6114418282612207565b5050565b606061144f611633565b905060005b815181101561144157600082828151811061146b57fe5b602002602001015190506000600560009054906101000a90046001600160a01b03166001600160a01b031663dacb2d0183846040516020016114ad9190613cca565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016114d9929190613dcc565b60206040518083038186803b1580156114f157600080fd5b505afa158015611505573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061152991908101906131c0565b6000838152600660205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68906115859084908490613d95565b60405180910390a15050600101611454565b6001546001600160a01b031633146115c15760405162461bcd60e51b815260040161084f90613e99565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c92611604926001600160a01b0391821692911690613cfc565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60608061163e612833565b60408051600e8082526101e0820190925291925060609190602082016101c0803883390190505090507f53797374656d53746174757300000000000000000000000000000000000000008160008151811061169557fe5b6020026020010181815250507f53796e7468657469784465627453686172650000000000000000000000000000816001815181106116cf57fe5b6020026020010181815250507f466565506f6f6c457465726e616c53746f7261676500000000000000000000008160028151811061170957fe5b6020026020010181815250507f45786368616e67657200000000000000000000000000000000000000000000008160038151811061174357fe5b6020026020010181815250506524b9b9bab2b960d11b8160048151811061176657fe5b6020026020010181815250507f526577617264457363726f775632000000000000000000000000000000000000816005815181106117a057fe5b6020026020010181815250507f44656c6567617465417070726f76616c73000000000000000000000000000000816006815181106117da57fe5b6020026020010181815250507f52657761726473446973747269627574696f6e000000000000000000000000008160078151811061181457fe5b6020026020010181815250507f436f6c6c61746572616c4d616e616765720000000000000000000000000000008160088151811061184e57fe5b6020026020010181815250507f57726170706572466163746f72790000000000000000000000000000000000008160098151811061188857fe5b6020026020010181815250507f457468657257726170706572000000000000000000000000000000000000000081600a815181106118c257fe5b6020026020010181815250507f6578743a41676772656761746f7249737375656453796e74687300000000000081600b815181106118fc57fe5b6020026020010181815250507f6578743a41676772656761746f7244656274526174696f00000000000000000081600c8151811061193657fe5b6020026020010181815250507f467574757265734d61726b65744d616e6167657200000000000000000000000081600d8151811061197057fe5b6020026020010181815250506119868282612892565b9250505090565b6000546001600160a01b031681565b6119a4611e6b565b600280546001600160a01b0319166001600160a01b0383161790556040517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9061080f908390613cee565b60006119f96130b4565b611a0283610b25565b60200151519392505050565b6000610824611aa6611a1e612947565b732ad7ccaac0eeb396c3a5fc2b73a885435688c0d563907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611a6257600080fd5b505af4158015611a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a9a9190810190613236565b9063ffffffff611e4616565b611aae6129be565b9063ffffffff612a3516565b60006108246129be565b611acc612a5f565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b600281565b6000611afd6121dc565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015611b3557600080fd5b505afa158015611b49573d6000803e3d6000fd5b50505050611b556126e9565b600354610824906001600160a01b0316612753565b6003546001600160a01b031681565b6000610824612947565b73feefeefeefeefeefeefeefeefeefeefeefeefeef81565b6002546001600160a01b031681565b611bb2612a89565b6004544210611bd35760405162461bcd60e51b815260040161084f90613f89565b60028710611bf35760405162461bcd60e51b815260040161084f90613fa9565b6040518061010001604052808767ffffffffffffffff1681526020018667ffffffffffffffff16815260200160008152602001600081526020018581526020018481526020018381526020018281525060088860028110611c5057fe5b8251600791909102919091018054602084015167ffffffffffffffff90811668010000000000000000026fffffffffffffffff0000000000000000199190941667ffffffffffffffff19909216919091171691909117815560408201516001820155606082015160028201556080820151600382015560a0820151600482015560c0820151600582015560e09091015160069091015586611d5157611cf3612af7565b6001600160a01b03166331e6da5a876040518263ffffffff1660e01b8152600401611d1e9190613fd9565b600060405180830381600087803b158015611d3857600080fd5b505af1158015611d4c573d6000803e3d6000fd5b505050505b50505050505050565b611d626126e9565b611d6a612b0b565b6003546001600160a01b03908116911614611d975760405162461bcd60e51b815260040161084f90613f09565b611db581611da56000611df1565b600501549063ffffffff611e4616565b611dbf6000611df1565b6005015550565b60006108247f466565506f6f6c457465726e616c53746f726167650000000000000000000000612102565b60006008600260ff16836016540181611e0657fe5b0660028110611e1157fe5b6007020192915050565b60006108247f53796e7468657469784465627453686172650000000000000000000000000000612102565b6000828201838110156107315760405162461bcd60e51b815260040161084f90613ec9565b6000546001600160a01b03163314611e955760405162461bcd60e51b815260040161084f90613f49565b565b6000611ea1612b36565b6001600160a01b03166323257c2b7f53797374656d53657474696e67730000000000000000000000000000000000007f666565506572696f644475726174696f6e0000000000000000000000000000006040518363ffffffff1660e01b8152600401611f0e929190613dbe565b60206040518083038186803b158015611f2657600080fd5b505afa158015611f3a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108249190810190613236565b6000611f68612b61565b6001600160a01b0316826001600160a01b0316148061200a57506000611f8c612af7565b6001600160a01b03166316b2213f846040518263ffffffff1660e01b8152600401611fb79190613ce0565b60206040518083038186803b158015611fcf57600080fd5b505afa158015611fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120079190810190613236565b14155b806120935750612018612b8c565b6001600160a01b031663b38988f7836040518263ffffffff1660e01b81526004016120439190613ce0565b60206040518083038186803b15801561205b57600080fd5b505afa15801561206f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120939190810190613218565b806120b657506120a1612bb7565b6001600160a01b0316826001600160a01b0316145b806120d957506120c4612be2565b6001600160a01b0316826001600160a01b0316145b8061062057506120e7612c0d565b6001600160a01b0316826001600160a01b0316149050919050565b60008181526006602090815260408083205490516001600160a01b03909116918215159161213291869101613caa565b604051602081830303815290604052906110fb5760405162461bcd60e51b815260040161084f9190613e78565b600061073183836b033b2e3c9fd0803ce8000000612c38565b6000808261218b575060009050806121d5565b600061219685611df1565b905060006121b1858360030154612a3590919063ffffffff16565b905060006121cc868460050154612a3590919063ffffffff16565b91945090925050505b9250929050565b60006108247f53797374656d5374617475730000000000000000000000000000000000000000612102565b61220f612c0d565b6001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561224957600080fd5b505af115801561225d573d6000803e3d6000fd5b50505050612269612be2565b6001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156122a357600080fd5b505af11580156122b7573d6000803e3d6000fd5b50505050806122c66000611df1565b60020155816122d56000611df1565b6001015560006122e481611df1565b905060006122f26001611df1565b90506123178260030154611a9a836004015484600301546125cd90919063ffffffff16565b6123216000611df1565b6003015560058083015460068301549183015461234892611a9a919063ffffffff6125cd16565b6123526000611df1565b60050155600061236181611df1565b60030154111561243557612373612af7565b6001600160a01b031663c81ff8fa60075473feefeefeefeefeefeefeefeefeefeefeefeefeef6123a36000611df1565b600301546040518463ffffffff1660e01b81526004016123c593929190613da3565b602060405180830381600087803b1580156123df57600080fd5b505af11580156123f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124179190810190613218565b506124226000611df1565b600301546124306000611df1565b600401555b60165461246e9060029061246290600190612456908463ffffffff611e4616565b9063ffffffff6125cd16565b9063ffffffff612c7d16565b60168190556008906002811061248057fe5b6007020180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000168155600060018201819055600282018190556003820181905560048201819055600582018190556006909101819055429081906124e490611df1565b805467ffffffffffffffff191667ffffffffffffffff929092169190911790554261250f6000611df1565b805467ffffffffffffffff9290921668010000000000000000026fffffffffffffffff00000000000000001990921691909117905561254c612af7565b6001600160a01b03166331e6da5a826040518263ffffffff1660e01b81526004016125779190613fd9565b600060405180830381600087803b15801561259157600080fd5b505af11580156125a5573d6000803e3d6000fd5b505050506125c66125b66001611df1565b5467ffffffffffffffff16612cad565b5050505050565b6000828211156125ef5760405162461bcd60e51b815260040161084f90613ed9565b50900390565b600080600080612603612af7565b6001600160a01b031663ae3bbbbb866040518263ffffffff1660e01b815260040161262e9190613ce0565b604080518083038186803b15801561264557600080fd5b505afa158015612659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061267d9190810190613272565b91509150600061268b6129be565b9050808310156126a357506001935091506107b79050565b60006126c06126b3611a1e612947565b839063ffffffff612a3516565b9050808411156126da5760008395509550505050506107b7565b50600194509092505050915091565b6002546001600160a01b0316331480159061270f57506003546001600160a01b03163314155b15611e9557600380546001600160a01b03191633179055565b60006108247f44656c6567617465417070726f76616c73000000000000000000000000000000612102565b6000808080808080612764886125f5565b91509150816127855760405162461bcd60e51b815260040161084f90613f59565b80156127a35760405162461bcd60e51b815260040161084f90613f19565b6127ac8861073a565b9094509250831515806127bf5750600083115b6127db5760405162461bcd60e51b815260040161084f90613ef9565b6127f9886127e96001611df1565b5467ffffffffffffffff16612d65565b839450600083111561281a5761280e83612de2565b955061281a8887612eac565b612825888688612f5e565b506001979650505050505050565b604080516001808252818301909252606091602080830190803883390190505090507f466c657869626c6553746f7261676500000000000000000000000000000000008160008151811061288357fe5b60200260200101818152505090565b606081518351016040519080825280602002602001820160405280156128c2578160200160208202803883390190505b50905060005b8351811015612904578381815181106128dd57fe5b60200260200101518282815181106128f157fe5b60209081029190910101526001016128c8565b5060005b82518110156110fb5782818151811061291d57fe5b602002602001015182828651018151811061293457fe5b6020908102919091010152600101612908565b6000612951612b36565b6001600160a01b03166323257c2b7f53797374656d53657474696e67730000000000000000000000000000000000007f7461726765745468726573686f6c6400000000000000000000000000000000006040518363ffffffff1660e01b8152600401611f0e929190613dbe565b60006129c8612b36565b6001600160a01b03166323257c2b7f53797374656d53657474696e67730000000000000000000000000000000000007f69737375616e6365526174696f000000000000000000000000000000000000006040518363ffffffff1660e01b8152600401611f0e929190613dbe565b6000670de0b6b3a7640000612a50848463ffffffff61301a16565b81612a5757fe5b049392505050565b6002546001600160a01b03163314611e955760405162461bcd60e51b815260040161084f90613fb9565b6002546001600160a01b03163314801590612aaf57506003546001600160a01b03163314155b15612ac757600380546001600160a01b031916331790555b6000546003546001600160a01b03908116911614611e955760405162461bcd60e51b815260040161084f90613eb9565b60006108246524b9b9bab2b960d11b612102565b60006108247f52657761726473446973747269627574696f6e00000000000000000000000000612102565b60006108247f466c657869626c6553746f726167650000000000000000000000000000000000612102565b60006108247f45786368616e6765720000000000000000000000000000000000000000000000612102565b60006108247f436f6c6c61746572616c4d616e61676572000000000000000000000000000000612102565b60006108247f467574757265734d61726b65744d616e61676572000000000000000000000000612102565b60006108247f57726170706572466163746f7279000000000000000000000000000000000000612102565b60006108247f4574686572577261707065720000000000000000000000000000000000000000612102565b600080612c5e84612c5287600a870263ffffffff61301a16565b9063ffffffff61305416565b90506005600a820610612c6f57600a015b600a900490505b9392505050565b600081612c9c5760405162461bcd60e51b815260040161084f90613f29565b818381612ca557fe5b069392505050565b6002546040516001600160a01b039091169063907dff9790612cd3908490602001613d87565b6040516020818303038152906040526001604051612cf090613cd5565b6040519081900381207fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168252612d3793929160009081908190600401613e0b565b600060405180830381600087803b158015612d5157600080fd5b505af11580156125c6573d6000803e3d6000fd5b612d6d611dc6565b6001600160a01b0316633562fd207f6c6173745f6665655f7769746864726177616c0000000000000000000000000084604051602001612dae929190613c79565b60405160208183030381529060405280519060200120836040518363ffffffff1660e01b8152600401610eee929190613dbe565b6000818160015b6002811015612ea4576000612e1d612e0083611df1565b60060154612e0d84611df1565b600501549063ffffffff6125cd16565b90508015612e9a576000848210612e345784612e36565b815b9050612e5581612e4585611df1565b600601549063ffffffff611e4616565b612e5e84611df1565b60060155612e72858263ffffffff6125cd16565b9450612e84848263ffffffff611e4616565b935084612e98578395505050505050610623565b505b5060001901612de9565b509392505050565b816001600160a01b03811673feefeefeefeefeefeefeefeefeefeefeefeefeef1415612eea5760405162461bcd60e51b815260040161084f90613f99565b6301dfe200612ef7613089565b6001600160a01b0316631bb47b448585846040518463ffffffff1660e01b8152600401612f2693929190613d32565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b5050505050505050565b6002546040516001600160a01b039091169063907dff9790612f8890869086908690602001613d32565b6040516020818303038152906040526001604051612fa590613c9f565b6040519081900381207fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168252612fec93929160009081908190600401613e0b565b600060405180830381600087803b15801561300657600080fd5b505af1158015611d51573d6000803e3d6000fd5b60008261302957506000610734565b8282028284828161303657fe5b04146107315760405162461bcd60e51b815260040161084f90613f69565b60008082116130755760405162461bcd60e51b815260040161084f90613ee9565b600082848161308057fe5b04949350505050565b60006108247f526577617264457363726f775632000000000000000000000000000000000000612102565b60405180604001604052806002905b6130cb61313a565b8152602001906001900390816130c35790505090565b604051806101000160405280600067ffffffffffffffff168152602001600067ffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180604001604052806002906020820280388339509192915050565b803561073481614145565b805161073481614145565b80516107348161415c565b805161073481614165565b803561073481614165565b80516107348161416e565b6000602082840312156131ac57600080fd5b60006131b88484613158565b949350505050565b6000602082840312156131d257600080fd5b60006131b88484613163565b600080604083850312156131f157600080fd5b60006131fd8585613158565b925050602061320e85828601613184565b9150509250929050565b60006020828403121561322a57600080fd5b60006131b8848461316e565b60006020828403121561324857600080fd5b60006131b88484613179565b60006020828403121561326657600080fd5b60006131b88484613184565b6000806040838503121561328557600080fd5b60006132918585613179565b925050602061320e8582860161316e565b600080604083850312156132b557600080fd5b60006131fd8585613184565b600080600080600080600060e0888a0312156132dc57600080fd5b60006132e88a8a613184565b97505060206132f98a828b01613184565b965050604061330a8a828b01613184565b955050606061331b8a828b01613184565b945050608061332c8a828b01613184565b93505060a061333d8a828b01613184565b92505060c061334e8a828b01613184565b91505092959891949750929550565b600080600080600060a0868803121561337557600080fd5b6000613381888861318f565b955050602061339288828901613179565b94505060406133a388828901613179565b93505060606133b488828901613179565b92505060806133c58882890161318f565b9150509295509295909350565b60006133de83836134c8565b505060400190565b60006133f2838361351d565b505060200190565b613403816140c9565b82525050565b61340381614076565b61340361341e82614076565b614124565b61342c81614063565b6134368184610623565b925061344182610827565b8060005b83811015610f1c57815161345987826133d2565b96506134648361405d565b925050600101613445565b600061347a82614069565b613484818561406d565b935061348f8361405d565b8060005b838110156134bd5781516134a788826133e6565b97506134b28361405d565b925050600101613493565b509495945050505050565b6134d181614063565b6134db8184610623565b92506134e682610827565b8060005b83811015610f1c5781516134fe87826133e6565b96506135098361405d565b9250506001016134ea565b61340381614081565b61340381610827565b61340361353282610827565b610827565b600061354282614069565b61354c818561406d565b935061355c8185602086016140f4565b61356581614135565b9093019392505050565b613403816140d0565b613403816140db565b613403816140e9565b600061359760178361406d565b7f4f6e6c7920496e7465726e616c20436f6e747261637473000000000000000000815260200192915050565b60006135d060358361406d565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527f2063616e20616363657074206f776e6572736869700000000000000000000000602082015260400192915050565b600061362f601d8361406d565b7f546f6f206561726c7920746f20636c6f73652066656520706572696f64000000815260200192915050565b600061366860138361406d565b7f4f776e6572206f6e6c792066756e6374696f6e00000000000000000000000000815260200192915050565b60006136a1602483610623565b7f46656573436c61696d656428616464726573732c75696e743235362c75696e7481527f3235362900000000000000000000000000000000000000000000000000000000602082015260240192915050565b6000613700601b8361406d565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613739601e8361406d565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000613772601a8361406d565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b60006137ab60408361406d565b7f4e6f2066656573206f72207265776172647320617661696c61626c6520666f7281527f20706572696f642c206f72206665657320616c726561647920636c61696d6564602082015260400192915050565b600061380a602b8361406d565b7f4d697373696e6720636f6e74726163743a2053796e746865746978427269646781527f65546f4f7074696d69736d000000000000000000000000000000000000000000602082015260400192915050565b6000613869601183610623565b7f4d697373696e6720616464726573733a20000000000000000000000000000000815260110192915050565b60006138a260188361406d565b7f52657761726473446973747269627574696f6e206f6e6c790000000000000000815260200192915050565b60006138db601e8361406d565b7f412073796e7468206f7220534e58207261746520697320696e76616c69640000815260200192915050565b600061391460188361406d565b7f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815260200192915050565b600061394d601f8361406d565b7f4e6f7420617070726f76656420746f20636c61696d206f6e20626568616c6600815260200192915050565b6000613986602f8361406d565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681527f6f726d207468697320616374696f6e0000000000000000000000000000000000602082015260400192915050565b60006139e5601f8361406d565b7f432d526174696f2062656c6f772070656e616c7479207468726573686f6c6400815260200192915050565b6000613a1e60218361406d565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f81527f7700000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613a7d601b8361406d565b7f4f6e6c792076616c69642072656c617965722063616e2063616c6c0000000000815260200192915050565b6000613ab660298361406d565b7f43616e206f6e6c7920706572666f726d207468697320616374696f6e2064757281527f696e672073657475700000000000000000000000000000000000000000000000602082015260400192915050565b6000613b15601983610623565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000613b4e60178361406d565b7f4665652061646472657373206e6f7420616c6c6f776564000000000000000000815260200192915050565b6000613b8760188361406d565b7f696e76616c69642066656520706572696f6420696e6465780000000000000000815260200192915050565b6000613bc0601883610623565b7f466565506572696f64436c6f7365642875696e74323536290000000000000000815260180192915050565b6000613bf960178361406d565b7f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000815260200192915050565b6000613c32601b8361406d565b7f46656520506572696f64204475726174696f6e206e6f74207365740000000000815260200192915050565b61340381614086565b613403816140a7565b613403816140b4565b6000613c858285613526565b602082019150613c958284613412565b5060140192915050565b600061073482613694565b6000613cb58261385c565b9150613cc18284613526565b50602001919050565b6000613cb582613b08565b600061073482613bb3565b602081016107348284613409565b6020810161073482846133fa565b60408101613d0a8285613409565b612c766020830184613409565b60408101613d258285613409565b612c76602083018461351d565b60608101613d408286613409565b613d4d602083018561351d565b6131b8604083018461351d565b608081016107348284613423565b60208082528101610731818461346f565b602081016107348284613514565b60208101610734828461351d565b60408101613d0a828561351d565b60608101613db1828661351d565b613d4d6020830185613409565b60408101613d25828561351d565b60408101613dda828561351d565b81810360208301526131b88184613537565b60408101613dfa828461351d565b8181036020830152610731816137fd565b60c08082528101613e1c8189613537565b9050613e2b6020830188613581565b613e38604083018761351d565b613e456060830186613578565b613e526080830185613578565b613e5f60a0830184613578565b979650505050505050565b60208101610734828461356f565b602080825281016107318184613537565b602080825281016106208161358a565b60208082528101610620816135c3565b6020808252810161062081613622565b602080825281016106208161365b565b60208082528101610620816136f3565b602080825281016106208161372c565b6020808252810161062081613765565b602080825281016106208161379e565b6020808252810161062081613895565b60208082528101610620816138ce565b6020808252810161062081613907565b6020808252810161062081613940565b6020808252810161062081613979565b60208082528101610620816139d8565b6020808252810161062081613a11565b6020808252810161062081613a70565b6020808252810161062081613aa9565b6020808252810161062081613b41565b6020808252810161062081613b7a565b6020808252810161062081613bec565b6020808252810161062081613c25565b602081016107348284613c5e565b60e08101613ff5828a613c67565b6140026020830189613c67565b61400f6040830188613c67565b61401c606083018761351d565b614029608083018661351d565b61403660a083018561351d565b61404360c083018461351d565b98975050505050505050565b602081016107348284613c70565b60200190565b50600290565b5190565b90815260200190565b60006106208261409b565b151590565b6fffffffffffffffffffffffffffffffff1690565b6001600160a01b031690565b67ffffffffffffffff1690565b60ff1690565b69ffffffffffffffffffff1690565b6000610620825b600061062082614076565b600061062061353283610827565b600061062082610827565b60005b8381101561410f5781810151838201526020016140f7565b8381111561411e576000848401525b50505050565b60006106208260006106208261413f565b601f01601f191690565b60601b90565b61414e81614076565b811461415957600080fd5b50565b61414e81614081565b61414e81610827565b61414e816140ba56fea365627a7a7231582084a26b19e4e7aa56460b87d9fffabf4826221553c03ca462841e08c17a2953176c6578706572696d656e74616cf564736f6c63430005100040

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000038fc5d5a5402cde8cb384c939d201522f087322900000000000000000000000048914229dedd5a9922f44441ffccfc2cb7856ee9000000000000000000000000529c553ef2d0370279dc8abf19702b98b166d252

-----Decoded View---------------
Arg [0] : _proxy (address): 0x38fC5D5A5402Cde8cB384c939d201522F0873229
Arg [1] : _owner (address): 0x48914229deDd5A9922f44441ffCCfC2Cb7856Ee9
Arg [2] : _resolver (address): 0x529C553eF2d0370279DC8AbF19702B98b166D252

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000038fc5d5a5402cde8cb384c939d201522f0873229
Arg [1] : 00000000000000000000000048914229dedd5a9922f44441ffccfc2cb7856ee9
Arg [2] : 000000000000000000000000529c553ef2d0370279dc8abf19702b98b166d252


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.