ETH Price: $3,445.20 (+2.83%)
Gas: 57 Gwei

Contract

0x21bD6b9C3cB3f7E0c6Aa7061D2B02f22CDEbD2aB
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Close Current Fe...103277852020-06-24 9:57:191346 days ago1592992639IN
Synthetix: Old Fee Pool 13
0 ETH0.0018484132
Claim On Behalf103259422020-06-24 3:02:311346 days ago1592967751IN
Synthetix: Old Fee Pool 13
0 ETH0.0286689726.69185744
Claim On Behalf103257292020-06-24 2:15:211346 days ago1592964921IN
Synthetix: Old Fee Pool 13
0 ETH0.0296633826.76638346
Claim On Behalf103256952020-06-24 2:08:261346 days ago1592964506IN
Synthetix: Old Fee Pool 13
0 ETH0.0295143727.86385816
Claim On Behalf103254332020-06-24 1:08:341346 days ago1592960914IN
Synthetix: Old Fee Pool 13
0 ETH0.035787732.55863422
Claim On Behalf103254132020-06-24 1:04:121346 days ago1592960652IN
Synthetix: Old Fee Pool 13
0 ETH0.0356640933.86016505
Claim On Behalf103253472020-06-24 0:50:331346 days ago1592959833IN
Synthetix: Old Fee Pool 13
0 ETH0.0330955131.24962918
Claim On Behalf103252982020-06-24 0:37:031346 days ago1592959023IN
Synthetix: Old Fee Pool 13
0 ETH0.0333063831.44785237
Claim On Behalf103250922020-06-23 23:49:361346 days ago1592956176IN
Synthetix: Old Fee Pool 13
0 ETH0.0301140428.59165351
Claim On Behalf103250722020-06-23 23:45:291346 days ago1592955929IN
Synthetix: Old Fee Pool 13
0 ETH0.0316085629.84460414
Claim On Behalf103249162020-06-23 23:09:451346 days ago1592953785IN
Synthetix: Old Fee Pool 13
0 ETH0.0259141424.1240921
Claim On Behalf103247632020-06-23 22:35:161346 days ago1592951716IN
Synthetix: Old Fee Pool 13
0 ETH0.0234913621.87051802
Claim On Behalf103245192020-06-23 21:39:461346 days ago1592948386IN
Synthetix: Old Fee Pool 13
0 ETH0.0237411722.41651492
Claim On Behalf103244442020-06-23 21:23:051346 days ago1592947385IN
Synthetix: Old Fee Pool 13
0 ETH0.0271589525.28533455
Claim On Behalf103243992020-06-23 21:12:421347 days ago1592946762IN
Synthetix: Old Fee Pool 13
0 ETH0.027266425.88856001
Claim On Behalf103243732020-06-23 21:08:121347 days ago1592946492IN
Synthetix: Old Fee Pool 13
0 ETH0.0268117625.45660323
Claim On Behalf103243132020-06-23 20:56:251347 days ago1592945785IN
Synthetix: Old Fee Pool 13
0 ETH0.0250086623.61314674
Claim On Behalf103242172020-06-23 20:33:131347 days ago1592944393IN
Synthetix: Old Fee Pool 13
0 ETH0.0248834723.49507864
Claim On Behalf103241902020-06-23 20:28:111347 days ago1592944091IN
Synthetix: Old Fee Pool 13
0 ETH0.025144423.87229694
Claim On Behalf103241412020-06-23 20:16:011347 days ago1592943361IN
Synthetix: Old Fee Pool 13
0 ETH0.024922823.3300606
Claim On Behalf103241302020-06-23 20:14:401347 days ago1592943280IN
Synthetix: Old Fee Pool 13
0 ETH0.0251857923.91173048
Claim On Behalf103241052020-06-23 20:08:561347 days ago1592942936IN
Synthetix: Old Fee Pool 13
0 ETH0.0261238424.80204513
Claim On Behalf103240842020-06-23 20:05:411347 days ago1592942741IN
Synthetix: Old Fee Pool 13
0 ETH0.0263705724.89849697
Claim On Behalf103240602020-06-23 20:00:331347 days ago1592942433IN
Synthetix: Old Fee Pool 13
0 ETH0.0265090525.02667825
Claim On Behalf103240312020-06-23 19:55:171347 days ago1592942117IN
Synthetix: Old Fee Pool 13
0 ETH0.0281800126.75463464
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
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 Etherscan.io on 2020-06-05
*/

/*

⚠⚠⚠ 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/ProxyFeePool

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

* 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
*	- Owned
*	- Proxyable
*	- SelfDestructible
*	- State
* Libraries: 
*	- SafeDecimalMath
*	- SafeMath
*
* MIT License
* ===========
*
* Copyright (c) 2020 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
*/

/* ===============================================
* Flattened with Solidifier by Coinage
* 
* https://solidifier.coina.ge
* ===============================================
*/


pragma solidity ^0.5.16;


// https://docs.synthetix.io/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 {
        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/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/Proxyable
contract Proxyable is Owned {
    // This contract should be treated like an abstract contract

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

    /* 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 setIntegrationProxy(address payable _integrationProxy) external onlyOwner {
        integrationProxy = Proxy(_integrationProxy);
    }

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

    modifier onlyProxy {
        require(Proxy(msg.sender) == proxy || Proxy(msg.sender) == integrationProxy, "Only the proxy can call");
        _;
    }

    modifier optionalProxy {
        if (Proxy(msg.sender) != proxy && Proxy(msg.sender) != integrationProxy && messageSender != msg.sender) {
            messageSender = msg.sender;
        }
        _;
    }

    modifier optionalProxy_onlyOwner {
        if (Proxy(msg.sender) != proxy && Proxy(msg.sender) != integrationProxy && messageSender != msg.sender) {
            messageSender = msg.sender;
        }
        require(messageSender == owner, "Owner only function");
        _;
    }

    event ProxyUpdated(address proxyAddress);
}


// Inheritance


// https://docs.synthetix.io/contracts/SelfDestructible
contract SelfDestructible is Owned {
    uint public constant SELFDESTRUCT_DELAY = 4 weeks;

    uint public initiationTime;
    bool public selfDestructInitiated;

    address public selfDestructBeneficiary;

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

    /**
     * @notice Set the beneficiary address of this contract.
     * @dev Only the contract owner may call this. The provided beneficiary must be non-null.
     * @param _beneficiary The address to pay any eth contained in this contract to upon self-destruction.
     */
    function setSelfDestructBeneficiary(address payable _beneficiary) external onlyOwner {
        require(_beneficiary != address(0), "Beneficiary must not be zero");
        selfDestructBeneficiary = _beneficiary;
        emit SelfDestructBeneficiaryUpdated(_beneficiary);
    }

    /**
     * @notice Begin the self-destruction counter of this contract.
     * Once the delay has elapsed, the contract may be self-destructed.
     * @dev Only the contract owner may call this.
     */
    function initiateSelfDestruct() external onlyOwner {
        initiationTime = now;
        selfDestructInitiated = true;
        emit SelfDestructInitiated(SELFDESTRUCT_DELAY);
    }

    /**
     * @notice Terminate and reset the self-destruction timer.
     * @dev Only the contract owner may call this.
     */
    function terminateSelfDestruct() external onlyOwner {
        initiationTime = 0;
        selfDestructInitiated = false;
        emit SelfDestructTerminated();
    }

    /**
     * @notice If the self-destruction delay has elapsed, destroy this contract and
     * remit any ether it owns to the beneficiary address.
     * @dev Only the contract owner may call this.
     */
    function selfDestruct() external onlyOwner {
        require(selfDestructInitiated, "Self Destruct not yet initiated");
        require(initiationTime + SELFDESTRUCT_DELAY < now, "Self destruct delay not met");
        emit SelfDestructed(selfDestructBeneficiary);
        selfdestruct(address(uint160(selfDestructBeneficiary)));
    }

    event SelfDestructTerminated();
    event SelfDestructed(address beneficiary);
    event SelfDestructInitiated(uint selfDestructDelay);
    event SelfDestructBeneficiaryUpdated(address newBeneficiary);
}


// https://docs.synthetix.io/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");
        _;
    }
}


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


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


interface ISynthetix {
    // Views
    function availableCurrencyKeys() external view returns (bytes32[] memory);

    function availableSynthCount() external view returns (uint);

    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 debtBalanceOfAndTotalDebt(address issuer, bytes32 currencyKey)
        external
        view
        returns (uint debtBalance, uint totalSystemValue);

    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 totalIssuedSynthsExcludeEtherCollateral(bytes32 currencyKey) external view returns (uint);

    function transferableSynthetix(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 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
        );

    function liquidateDelinquentAccount(address account, uint susdAmount) external returns (bool);
}


// Inheritance


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

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

    /* ========== MUTATIVE 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++) {
            repository[names[i]] = destinations[i];
        }
    }

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

    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) {
        ISynthetix synthetix = ISynthetix(repository["Synthetix"]);
        require(address(synthetix) != address(0), "Cannot find Synthetix address");
        return address(synthetix.synths(key));
    }
}


// Inheritance


// Internal references


// https://docs.synthetix.io/contracts/MixinResolver
contract MixinResolver is Owned {
    AddressResolver public resolver;

    mapping(bytes32 => address) private addressCache;

    bytes32[] public resolverAddressesRequired;

    uint public constant MAX_ADDRESSES_FROM_RESOLVER = 24;

    constructor(address _resolver, bytes32[MAX_ADDRESSES_FROM_RESOLVER] memory _addressesToCache) internal {
        // This contract is abstract, and thus cannot be instantiated directly
        require(owner != address(0), "Owner must be set");

        for (uint i = 0; i < _addressesToCache.length; i++) {
            if (_addressesToCache[i] != bytes32(0)) {
                resolverAddressesRequired.push(_addressesToCache[i]);
            } else {
                // End early once an empty item is found - assumes there are no empty slots in
                // _addressesToCache
                break;
            }
        }
        resolver = AddressResolver(_resolver);
        // Do not sync the cache as addresses may not be in the resolver yet
    }

    /* ========== SETTERS ========== */
    function setResolverAndSyncCache(AddressResolver _resolver) external onlyOwner {
        resolver = _resolver;

        for (uint i = 0; i < resolverAddressesRequired.length; i++) {
            bytes32 name = resolverAddressesRequired[i];
            // Note: can only be invoked once the resolver has all the targets needed added
            addressCache[name] = resolver.requireAndGetAddress(name, "Resolver missing target");
        }
    }

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

    function requireAndGetAddress(bytes32 name, string memory reason) internal view returns (address) {
        address _foundAddress = addressCache[name];
        require(_foundAddress != address(0), reason);
        return _foundAddress;
    }

    // Note: this could be made external in a utility contract if addressCache was made public
    // (used for deployment)
    function isResolverCached(AddressResolver _resolver) external view returns (bool) {
        if (resolver != _resolver) {
            return false;
        }

        // otherwise, check everything
        for (uint i = 0; i < resolverAddressesRequired.length; i++) {
            bytes32 name = resolverAddressesRequired[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;
    }

    // Note: can be made external into a utility contract (used for deployment)
    function getResolverAddressesRequired()
        external
        view
        returns (bytes32[MAX_ADDRESSES_FROM_RESOLVER] memory addressesRequired)
    {
        for (uint i = 0; i < resolverAddressesRequired.length; i++) {
            addressesRequired[i] = resolverAddressesRequired[i];
        }
    }

    /* ========== INTERNAL FUNCTIONS ========== */
    function appendToAddressCache(bytes32 name) internal {
        resolverAddressesRequired.push(name);
        require(resolverAddressesRequired.length < MAX_ADDRESSES_FROM_RESOLVER, "Max resolver cache size met");
        // Because this is designed to be called internally in constructors, we don't
        // check the address exists already in the resolver
        addressCache[name] = resolver.getAddress(name);
    }
}


interface IFeePool {
    // Views
    function getExchangeFeeRateForSynth(bytes32 synthKey) external view returns (uint);

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

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

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

    function totalFeesAvailable() 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;

    // Restricted: used internally to Synthetix
    function appendAccountIssuanceRecord(
        address account,
        uint lockedAmount,
        uint debtEntryIndex
    ) 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/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;
    }
}


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


interface ISystemStatus {
    // Views
    function requireSystemActive() external view;

    function requireIssuanceActive() external view;

    function requireExchangeActive() external view;

    function requireSynthActive(bytes32 currencyKey) external view;

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


interface IRewardEscrow {
    // Views
    function balanceOf(address account) external view returns (uint);

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

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

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

    // Mutative functions
    function appendVestingEntry(address account, uint quantity) external;

    function vest() external;
}


interface IExchangeRates {
    // Views
    function aggregators(bytes32 currencyKey) external view returns (address);

    function anyRateIsStale(bytes32[] calldata currencyKeys) external view returns (bool);

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

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

    function effectiveValueAtRound(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        uint roundIdForSrc,
        uint roundIdForDest
    ) external view returns (uint);

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

    function getLastRoundIdBeforeElapsedSecs(
        bytes32 currencyKey,
        uint startingRoundId,
        uint startingTimestamp,
        uint timediff
    ) external view returns (uint);

    function inversePricing(bytes32 currencyKey)
        external
        view
        returns (
            uint entryPoint,
            uint upperLimit,
            uint lowerLimit,
            bool frozen
        );

    function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256);

    function oracle() external view returns (address);

    function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time);

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

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

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

    function ratesAndStaleForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory, bool);

    function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory);

    function rateStalePeriod() external view returns (uint);
}


interface ISynthetixState {
    // Views
    function debtLedger(uint index) external view returns (uint);

    function issuanceRatio() external view returns (uint);

    function issuanceData(address account) external view returns (uint initialDebtOwnership, uint debtEntryIndex);

    function debtLedgerLength() external view returns (uint);

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

    function lastDebtLedgerEntry() external view returns (uint);

    // Mutative functions
    function incrementTotalIssuerCount() external;

    function decrementTotalIssuerCount() external;

    function setCurrentIssuanceData(address account, uint initialDebtOwnership) external;

    function appendDebtLedgerValue(uint value) external;

    function clearIssuanceData(address account) external;
}


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

    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 exchangeFeeRate);

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

    // Mutative functions
    function exchange(
        address from,
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        address destinationAddress
    ) external returns (uint amountReceived);

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

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


interface IIssuer {
    // Views
    function canBurnSynths(address account) external view returns (bool);

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

    // Restricted: used internally to Synthetix
    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 liquidateDelinquentAccount(address account, uint susdAmount, address liquidator) external returns (uint totalRedeemed, uint amountToLiquidate);
}


interface IRewardsDistribution {
    // Mutative functions
    function distributeRewards(uint amount) external returns (bool);
}


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


// Inheritance


// Libraries


// Internal references


// https://docs.synthetix.io/contracts/FeePoolState
contract FeePoolState is Owned, SelfDestructible, LimitedSetup {
    using SafeMath for uint;
    using SafeDecimalMath for uint;

    /* ========== STATE VARIABLES ========== */

    uint8 public constant FEE_PERIOD_LENGTH = 6;

    address public feePool;

    // The IssuanceData activity that's happened in a fee period.
    struct IssuanceData {
        uint debtPercentage;
        uint debtEntryIndex;
    }

    // The IssuanceData activity that's happened in a fee period.
    mapping(address => IssuanceData[FEE_PERIOD_LENGTH]) public accountIssuanceLedger;

    constructor(address _owner, IFeePool _feePool) public Owned(_owner) SelfDestructible() LimitedSetup(6 weeks) {
        feePool = address(_feePool);
    }

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

    /**
     * @notice set the FeePool contract as it is the only authority to be able to call
     * appendAccountIssuanceRecord with the onlyFeePool modifer
     * @dev Must be set by owner when FeePool logic is upgraded
     */
    function setFeePool(IFeePool _feePool) external onlyOwner {
        feePool = address(_feePool);
    }

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

    /**
     * @notice Get an accounts issuanceData for
     * @param account users account
     * @param index Index in the array to retrieve. Upto FEE_PERIOD_LENGTH
     */
    function getAccountsDebtEntry(address account, uint index)
        public
        view
        returns (uint debtPercentage, uint debtEntryIndex)
    {
        require(index < FEE_PERIOD_LENGTH, "index exceeds the FEE_PERIOD_LENGTH");

        debtPercentage = accountIssuanceLedger[account][index].debtPercentage;
        debtEntryIndex = accountIssuanceLedger[account][index].debtEntryIndex;
    }

    /**
     * @notice Find the oldest debtEntryIndex for the corresponding closingDebtIndex
     * @param account users account
     * @param closingDebtIndex the last periods debt index on close
     */
    function applicableIssuanceData(address account, uint closingDebtIndex) external view returns (uint, uint) {
        IssuanceData[FEE_PERIOD_LENGTH] memory issuanceData = accountIssuanceLedger[account];

        // We want to use the user's debtEntryIndex at when the period closed
        // Find the oldest debtEntryIndex for the corresponding closingDebtIndex
        for (uint i = 0; i < FEE_PERIOD_LENGTH; i++) {
            if (closingDebtIndex >= issuanceData[i].debtEntryIndex) {
                return (issuanceData[i].debtPercentage, issuanceData[i].debtEntryIndex);
            }
        }
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice Logs an accounts issuance data in the current fee period which is then stored historically
     * @param account Message.Senders account address
     * @param debtRatio Debt of this account as a percentage of the global debt.
     * @param debtEntryIndex The index in the global debt ledger. synthetix.synthetixState().issuanceData(account)
     * @param currentPeriodStartDebtIndex The startingDebtIndex of the current fee period
     * @dev onlyFeePool to call me on synthetix.issue() & synthetix.burn() calls to store the locked SNX
     * per fee period so we know to allocate the correct proportions of fees and rewards per period
      accountIssuanceLedger[account][0] has the latest locked amount for the current period. This can be update as many time
      accountIssuanceLedger[account][1-2] has the last locked amount for a previous period they minted or burned
     */
    function appendAccountIssuanceRecord(
        address account,
        uint debtRatio,
        uint debtEntryIndex,
        uint currentPeriodStartDebtIndex
    ) external onlyFeePool {
        // Is the current debtEntryIndex within this fee period
        if (accountIssuanceLedger[account][0].debtEntryIndex < currentPeriodStartDebtIndex) {
            // If its older then shift the previous IssuanceData entries periods down to make room for the new one.
            issuanceDataIndexOrder(account);
        }

        // Always store the latest IssuanceData entry at [0]
        accountIssuanceLedger[account][0].debtPercentage = debtRatio;
        accountIssuanceLedger[account][0].debtEntryIndex = debtEntryIndex;
    }

    /**
     * @notice Pushes down the entire array of debt ratios per fee period
     */
    function issuanceDataIndexOrder(address account) private {
        for (uint i = FEE_PERIOD_LENGTH - 2; i < FEE_PERIOD_LENGTH; i--) {
            uint next = i + 1;
            accountIssuanceLedger[account][next].debtPercentage = accountIssuanceLedger[account][i].debtPercentage;
            accountIssuanceLedger[account][next].debtEntryIndex = accountIssuanceLedger[account][i].debtEntryIndex;
        }
    }

    /**
     * @notice Import issuer data from synthetixState.issuerData on FeePeriodClose() block #
     * @dev Only callable by the contract owner, and only for 6 weeks after deployment.
     * @param accounts Array of issuing addresses
     * @param ratios Array of debt ratios
     * @param periodToInsert The Fee Period to insert the historical records into
     * @param feePeriodCloseIndex An accounts debtEntryIndex is valid when within the fee peroid,
     * since the input ratio will be an average of the pervious periods it just needs to be
     * > recentFeePeriods[periodToInsert].startingDebtIndex
     * < recentFeePeriods[periodToInsert - 1].startingDebtIndex
     */
    function importIssuerData(
        address[] calldata accounts,
        uint[] calldata ratios,
        uint periodToInsert,
        uint feePeriodCloseIndex
    ) external onlyOwner onlyDuringSetup {
        require(accounts.length == ratios.length, "Length mismatch");

        for (uint i = 0; i < accounts.length; i++) {
            accountIssuanceLedger[accounts[i]][periodToInsert].debtPercentage = ratios[i];
            accountIssuanceLedger[accounts[i]][periodToInsert].debtEntryIndex = feePeriodCloseIndex;
            emit IssuanceDebtRatioEntry(accounts[i], ratios[i], feePeriodCloseIndex);
        }
    }

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

    modifier onlyFeePool {
        require(msg.sender == address(feePool), "Only the FeePool contract can perform this action");
        _;
    }

    /* ========== Events ========== */
    event IssuanceDebtRatioEntry(address indexed account, uint debtRatio, uint feePeriodCloseIndex);
}


// Inheritance


// https://docs.synthetix.io/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


/**
 * @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.
 */
// https://docs.synthetix.io/contracts/EternalStorage
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/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]);
        }
    }
}


// Inheritance


// Libraries


// Internal references


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

    // Exchange fee may not exceed 10%.
    uint public constant MAX_EXCHANGE_FEE_RATE = 1e18 / 10;

    // 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 startingDebtIndex;
        uint64 startTime;
        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;

    // How long a fee period lasts at a minimum. It is required for
    // anyone to roll over the periods, so they are not guaranteed
    // to roll over at exactly this duration, but the contract enforces
    // that they cannot roll over any quicker than this duration.
    uint public feePeriodDuration = 1 weeks;
    // The fee period must be between 1 day and 60 days.
    uint public constant MIN_FEE_PERIOD_DURATION = 1 days;
    uint public constant MAX_FEE_PERIOD_DURATION = 60 days;

    // Users are unable to claim fees if their collateralisation ratio drifts out of target treshold
    uint public targetThreshold = (1 * SafeDecimalMath.unit()) / 100;

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

    bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus";
    bytes32 private constant CONTRACT_SYNTHETIX = "Synthetix";
    bytes32 private constant CONTRACT_FEEPOOLSTATE = "FeePoolState";
    bytes32 private constant CONTRACT_FEEPOOLETERNALSTORAGE = "FeePoolEternalStorage";
    bytes32 private constant CONTRACT_EXCHANGER = "Exchanger";
    bytes32 private constant CONTRACT_ISSUER = "Issuer";
    bytes32 private constant CONTRACT_SYNTHETIXSTATE = "SynthetixState";
    bytes32 private constant CONTRACT_REWARDESCROW = "RewardEscrow";
    bytes32 private constant CONTRACT_DELEGATEAPPROVALS = "DelegateApprovals";
    bytes32 private constant CONTRACT_REWARDSDISTRIBUTION = "RewardsDistribution";

    bytes32[24] private addressesToCache = [
        CONTRACT_SYSTEMSTATUS,
        CONTRACT_SYNTHETIX,
        CONTRACT_FEEPOOLSTATE,
        CONTRACT_FEEPOOLETERNALSTORAGE,
        CONTRACT_EXCHANGER,
        CONTRACT_ISSUER,
        CONTRACT_SYNTHETIXSTATE,
        CONTRACT_REWARDESCROW,
        CONTRACT_DELEGATEAPPROVALS,
        CONTRACT_REWARDSDISTRIBUTION
    ];

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

    bytes32 private constant LAST_FEE_WITHDRAWAL = "last_fee_withdrawal";
    bytes32 private constant SYNTH_EXCHANGE_FEE_RATE = "synth_exchange_fee_rate";

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

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

    function systemStatus() internal view returns (ISystemStatus) {
        return ISystemStatus(requireAndGetAddress(CONTRACT_SYSTEMSTATUS, "Missing SystemStatus address"));
    }

    function synthetix() internal view returns (ISynthetix) {
        return ISynthetix(requireAndGetAddress(CONTRACT_SYNTHETIX, "Missing Synthetix address"));
    }

    function feePoolState() internal view returns (FeePoolState) {
        return FeePoolState(requireAndGetAddress(CONTRACT_FEEPOOLSTATE, "Missing FeePoolState address"));
    }

    function feePoolEternalStorage() internal view returns (FeePoolEternalStorage) {
        return
            FeePoolEternalStorage(
                requireAndGetAddress(CONTRACT_FEEPOOLETERNALSTORAGE, "Missing FeePoolEternalStorage address")
            );
    }

    function exchanger() internal view returns (IExchanger) {
        return IExchanger(requireAndGetAddress(CONTRACT_EXCHANGER, "Missing Exchanger address"));
    }

    function issuer() internal view returns (IIssuer) {
        return IIssuer(requireAndGetAddress(CONTRACT_ISSUER, "Missing Issuer address"));
    }

    function synthetixState() internal view returns (ISynthetixState) {
        return ISynthetixState(requireAndGetAddress(CONTRACT_SYNTHETIXSTATE, "Missing SynthetixState address"));
    }

    function rewardEscrow() internal view returns (IRewardEscrow) {
        return IRewardEscrow(requireAndGetAddress(CONTRACT_REWARDESCROW, "Missing RewardEscrow address"));
    }

    function delegateApprovals() internal view returns (IDelegateApprovals) {
        return IDelegateApprovals(requireAndGetAddress(CONTRACT_DELEGATEAPPROVALS, "Missing DelegateApprovals address"));
    }

    function rewardsDistribution() internal view returns (IRewardsDistribution) {
        return
            IRewardsDistribution(requireAndGetAddress(CONTRACT_REWARDSDISTRIBUTION, "Missing RewardsDistribution address"));
    }

    function recentFeePeriods(uint index)
        external
        view
        returns (
            uint64 feePeriodId,
            uint64 startingDebtIndex,
            uint64 startTime,
            uint feesToDistribute,
            uint feesClaimed,
            uint rewardsToDistribute,
            uint rewardsClaimed
        )
    {
        FeePeriod memory feePeriod = _recentFeePeriodsStorage(index);
        return (
            feePeriod.feePeriodId,
            feePeriod.startingDebtIndex,
            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];
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice Logs an accounts issuance data per fee period
     * @param account Message.Senders account address
     * @param debtRatio Debt percentage this account has locked after minting or burning their synth
     * @param debtEntryIndex The index in the global debt ledger. synthetixState.issuanceData(account)
     * @dev onlyIssuer to call me on synthetix.issue() & synthetix.burn() calls to store the locked SNX
     * per fee period so we know to allocate the correct proportions of fees and rewards per period
     */
    function appendAccountIssuanceRecord(
        address account,
        uint debtRatio,
        uint debtEntryIndex
    ) external onlyIssuer {
        feePoolState().appendAccountIssuanceRecord(
            account,
            debtRatio,
            debtEntryIndex,
            _recentFeePeriodsStorage(0).startingDebtIndex
        );

        emitIssuanceDebtRatioEntry(account, debtRatio, debtEntryIndex, _recentFeePeriodsStorage(0).startingDebtIndex);
    }

    /**
     * @notice Set the fee period duration
     */
    function setFeePeriodDuration(uint _feePeriodDuration) external optionalProxy_onlyOwner {
        require(_feePeriodDuration >= MIN_FEE_PERIOD_DURATION, "value < MIN_FEE_PERIOD_DURATION");
        require(_feePeriodDuration <= MAX_FEE_PERIOD_DURATION, "value > MAX_FEE_PERIOD_DURATION");

        feePeriodDuration = _feePeriodDuration;

        emitFeePeriodDurationUpdated(_feePeriodDuration);
    }

    function setTargetThreshold(uint _percent) external optionalProxy_onlyOwner {
        require(_percent <= 50, "Threshold too high");
        targetThreshold = _percent.mul(SafeDecimalMath.unit()).div(100);
    }

    /**
     * @notice The Exchanger contract informs us when fees are paid.
     * @param amount susd amount in fees being paid.
     */
    function recordFeePaid(uint amount) external onlyExchangerOrSynth {
        // 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 {
        address rewardsAuthority = address(rewardsDistribution());
        require(messageSender == rewardsAuthority || msg.sender == rewardsAuthority, "Caller is not rewardsAuthority");
        // 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 {
        require(_recentFeePeriodsStorage(0).startTime <= (now - feePeriodDuration), "Too early to close fee period");

        systemStatus().requireIssuanceActive();

        // Note:  when FEE_PERIOD_LENGTH = 2, periodClosing is the current period & periodToRollover is the last open claimable period
        FeePeriod storage periodClosing = _recentFeePeriodsStorage(FEE_PERIOD_LENGTH - 2);
        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(FEE_PERIOD_LENGTH - 2).feesToDistribute = periodToRollover
            .feesToDistribute
            .sub(periodToRollover.feesClaimed)
            .add(periodClosing.feesToDistribute);
        _recentFeePeriodsStorage(FEE_PERIOD_LENGTH - 2).rewardsToDistribute = periodToRollover
            .rewardsToDistribute
            .sub(periodToRollover.rewardsClaimed)
            .add(periodClosing.rewardsToDistribute);

        // 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.
        // Increment periodId from the recent closed period feePeriodId
        _recentFeePeriodsStorage(0).feePeriodId = uint64(uint256(_recentFeePeriodsStorage(1).feePeriodId).add(1));
        _recentFeePeriodsStorage(0).startingDebtIndex = uint64(synthetixState().debtLedgerLength());
        _recentFeePeriodsStorage(0).startTime = uint64(now);

        emitFeePeriodClosed(_recentFeePeriodsStorage(1).feePeriodId);
    }

    /**
     * @notice Claim fees for last period when available or not already withdrawn.
     */
    function claimFees() external 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 optionalProxy returns (bool) {
        require(delegateApprovals().canClaimFor(claimingForAddress, messageSender), "Not approved to claim on behalf");

        return _claimFees(claimingForAddress);
    }

    function _claimFees(address claimingAddress) internal returns (bool) {
        systemStatus().requireIssuanceActive();

        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.
        require(isFeesClaimable(claimingAddress), "C-Ratio below penalty threshold");

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

        if (availableFees > 0) {
            // Record the fee payment in our recentFeePeriods
            feesPaid = _recordFeePayment(availableFees);

            // Send them their fees
            _payFees(claimingAddress, feesPaid);
        }

        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 startingDebtIndex,
        uint startTime,
        uint feesToDistribute,
        uint feesClaimed,
        uint rewardsToDistribute,
        uint rewardsClaimed
    ) public optionalProxy_onlyOwner onlyDuringSetup {
        require(startingDebtIndex <= synthetixState().debtLedgerLength(), "Cannot import bad data");

        _recentFeePeriods[_currentFeePeriod.add(feePeriodIndex).mod(FEE_PERIOD_LENGTH)] = FeePeriod({
            feePeriodId: uint64(feePeriodId),
            startingDebtIndex: uint64(startingDebtIndex),
            startTime: uint64(startTime),
            feesToDistribute: feesToDistribute,
            feesClaimed: feesClaimed,
            rewardsToDistribute: rewardsToDistribute,
            rewardsClaimed: rewardsClaimed
        });
    }

    function setExchangeFeeRateForSynths(bytes32[] calldata synthKeys, uint256[] calldata exchangeFeeRates) external optionalProxy_onlyOwner
    {
        require(synthKeys.length == exchangeFeeRates.length, "Array lengths dont match");
        for (uint i = 0; i < synthKeys.length; i++) {
            require(exchangeFeeRates[i] <= MAX_EXCHANGE_FEE_RATE, "MAX_EXCHANGE_FEE_RATE exceeded");
            feePoolEternalStorage().setUIntValue(
                keccak256(abi.encodePacked(SYNTH_EXCHANGE_FEE_RATE, synthKeys[i])),
                exchangeFeeRates[i]
            );
            emitExchangeFeeUpdated(synthKeys[i], exchangeFeeRates[i]);
        }
    }

    function getExchangeFeeRateForSynth(bytes32 synthKey) external view returns (uint exchangeFeeRate) {
        exchangeFeeRate = feePoolEternalStorage().getUIntValue(
            keccak256(abi.encodePacked(SYNTH_EXCHANGE_FEE_RATE, synthKey))
        );
    }

    /**
     * @notice Owner can escrow SNX. Owner to send the tokens to the RewardEscrow
     * @param account Address to escrow tokens for
     * @param quantity Amount of tokens to escrow
     */
    function appendVestingEntry(address account, uint quantity) public optionalProxy_onlyOwner {
        // Transfer SNX from messageSender to the Reward Escrow
        IERC20(address(synthetix())).transferFrom(messageSender, address(rewardEscrow()), quantity);

        // Create Vesting Entry
        rewardEscrow().appendVestingEntry(account, quantity);
    }

    /**
     * @notice Record the fee payment in our recentFeePeriods.
     * @param sUSDAmount The amount of fees priced in sUSD.
     */
    function _recordFeePayment(uint sUSDAmount) internal returns (uint) {
        // Don't assign to the parameter
        uint remainingToAllocate = sUSDAmount;

        uint feesPaid;
        // 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 feesAlreadyClaimed = _recentFeePeriodsStorage(i).feesClaimed;
            uint delta = _recentFeePeriodsStorage(i).feesToDistribute.sub(feesAlreadyClaimed);

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

                _recentFeePeriodsStorage(i).feesClaimed = feesAlreadyClaimed.add(amountInPeriod);
                remainingToAllocate = remainingToAllocate.sub(amountInPeriod);
                feesPaid = feesPaid.add(amountInPeriod);

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

                // We've exhausted feePeriods to distribute and no fees remain in last period
                // User last to claim would in this scenario have their remainder slashed
                if (i == 0 && remainingToAllocate > 0) {
                    remainingToAllocate = 0;
                }
            }
        }

        return feesPaid;
    }

    /**
     * @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;

                // We've exhausted feePeriods to distribute and no rewards remain in last period
                // User last to claim would in this scenario have their remainder slashed
                // due to rounding up of PreciseDecimal
                if (i == 0 && remainingToAllocate > 0) {
                    remainingToAllocate = 0;
                }
            }
        }
        return rewardPaid;
    }

    /**
     * @notice Send the fees to claiming address.
     * @param account The address to send the fees to.
     * @param sUSDAmount The amount of fees priced in sUSD.
     */
    function _payFees(address account, uint sUSDAmount) internal notFeeAddress(account) {
        // Grab the sUSD Synth
        ISynth sUSDSynth = synthetix().synths(sUSD);

        // NOTE: we do not control the FEE_ADDRESS so it is not possible to do an
        // ERC20.approve() transaction to allow this feePool to call ERC20.transferFrom
        // to the accounts address

        // Burn the source amount
        sUSDSynth.burn(FEE_ADDRESS, sUSDAmount);

        // Mint their new synths
        sUSDSynth.issue(account, sUSDAmount);
    }

    /**
     * @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) {
        // Record vesting entry for claiming address and amount
        // SNX already minted to rewardEscrow balance
        rewardEscrow().appendVestingEntry(account, snxAmount);
    }

    /**
     * @notice The total fees available in the system to be withdrawnn 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 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[2][FEE_PERIOD_LENGTH] 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 Check if a particular address is able to claim fees right now
     * @param account The address you want to query for
     */
    function isFeesClaimable(address account) public view returns (bool) {
        // Threshold is calculated from ratio % above the target ratio (issuanceRatio).
        //  0  <  10%:   Claimable
        // 10% > above:  Unable to claim
        uint ratio = synthetix().collateralisationRatio(account);
        uint targetRatio = synthetixState().issuanceRatio();

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

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

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

        return true;
    }

    /**
     * @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[2][FEE_PERIOD_LENGTH] memory results) {
        // What's the user's debt entry index and the debt they owe to the system at current feePeriod
        uint userOwnershipPercentage;
        uint debtEntryIndex;
        FeePoolState _feePoolState = feePoolState();

        (userOwnershipPercentage, debtEntryIndex) = _feePoolState.getAccountsDebtEntry(account, 0);

        // If they don't have any debt ownership and they never minted, they don't have any fees.
        // User ownership can reduce to 0 if user burns all synths,
        // however they could have fees applicable for periods they had minted in before so we check debtEntryIndex.
        if (debtEntryIndex == 0 && userOwnershipPercentage == 0) {
            uint[2][FEE_PERIOD_LENGTH] memory nullResults;
            return nullResults;
        }

        // 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, debtEntryIndex);

        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--) {
            uint next = i - 1;
            uint nextPeriodStartingDebtIndex = _recentFeePeriodsStorage(next).startingDebtIndex;

            // We can skip the period, as no debt minted during period (next period's startingDebtIndex is still 0)
            if (nextPeriodStartingDebtIndex > 0 && lastFeeWithdrawal < _recentFeePeriodsStorage(i).feePeriodId) {
                // We calculate a feePeriod's closingDebtIndex by looking at the next feePeriod's startingDebtIndex
                // we can use the most recent issuanceData[0] for the current feePeriod
                // else find the applicableIssuanceData for the feePeriod based on the StartingDebtIndex of the period
                uint closingDebtIndex = uint256(nextPeriodStartingDebtIndex).sub(1);

                // Gas optimisation - to reuse debtEntryIndex if found new applicable one
                // if applicable is 0,0 (none found) we keep most recent one from issuanceData[0]
                // return if userOwnershipPercentage = 0)
                (userOwnershipPercentage, debtEntryIndex) = _feePoolState.applicableIssuanceData(account, closingDebtIndex);

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

                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,
        uint debtEntryIndex
    ) 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);

        uint debtOwnershipForPeriod = ownershipPercentage;

        // If period has closed we want to calculate debtPercentage for the period
        if (period > 0) {
            uint closingDebtIndex = uint256(_recentFeePeriodsStorage(period - 1).startingDebtIndex).sub(1);
            debtOwnershipForPeriod = _effectiveDebtRatioForPeriod(closingDebtIndex, ownershipPercentage, debtEntryIndex);
        }

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

        uint rewardsFromPeriod = _recentFeePeriodsStorage(period).rewardsToDistribute.multiplyDecimal(
            debtOwnershipForPeriod
        );

        return (feesFromPeriod.preciseDecimalToDecimal(), rewardsFromPeriod.preciseDecimalToDecimal());
    }

    function _effectiveDebtRatioForPeriod(
        uint closingDebtIndex,
        uint ownershipPercentage,
        uint debtEntryIndex
    ) internal view returns (uint) {
        // Figure out their global debt percentage delta at end of fee Period.
        // This is a high precision integer.
        ISynthetixState _synthetixState = synthetixState();
        uint feePeriodDebtOwnership = _synthetixState
            .debtLedger(closingDebtIndex)
            .divideDecimalRoundPrecise(_synthetixState.debtLedger(debtEntryIndex))
            .multiplyDecimalRoundPrecise(ownershipPercentage);

        return feePeriodDebtOwnership;
    }

    function effectiveDebtRatioForPeriod(address account, uint period) external view returns (uint) {
        require(period != 0, "Current period is not closed yet");
        require(period < FEE_PERIOD_LENGTH, "Exceeds the FEE_PERIOD_LENGTH");

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

        uint closingDebtIndex = uint256(_recentFeePeriodsStorage(period - 1).startingDebtIndex).sub(1);

        uint ownershipPercentage;
        uint debtEntryIndex;
        (ownershipPercentage, debtEntryIndex) = feePoolState().applicableIssuanceData(account, closingDebtIndex);

        // internal function will check closingDebtIndex has corresponding debtLedger entry
        return _effectiveDebtRatioForPeriod(closingDebtIndex, ownershipPercentage, debtEntryIndex);
    }

    /**
     * @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) {
        uint targetRatio = synthetixState().issuanceRatio();

        return targetRatio.multiplyDecimal(SafeDecimalMath.unit().add(targetThreshold));
    }

    /**
     * @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 ========== */
    modifier onlyExchangerOrSynth {
        bool isExchanger = msg.sender == address(exchanger());
        bool isSynth = synthetix().synthsByAddress(msg.sender) != bytes32(0);

        require(isExchanger || isSynth, "Only Exchanger, Synths Authorised");
        _;
    }

    modifier onlyIssuer {
        require(msg.sender == address(issuer()), "FeePool: Only Issuer Authorised");
        _;
    }

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

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

    event IssuanceDebtRatioEntry(
        address indexed account,
        uint debtRatio,
        uint debtEntryIndex,
        uint feePeriodStartingDebtIndex
    );
    bytes32 private constant ISSUANCEDEBTRATIOENTRY_SIG = keccak256(
        "IssuanceDebtRatioEntry(address,uint256,uint256,uint256)"
    );

    function emitIssuanceDebtRatioEntry(
        address account,
        uint debtRatio,
        uint debtEntryIndex,
        uint feePeriodStartingDebtIndex
    ) internal {
        proxy._emit(
            abi.encode(debtRatio, debtEntryIndex, feePeriodStartingDebtIndex),
            2,
            ISSUANCEDEBTRATIOENTRY_SIG,
            bytes32(uint256(uint160(account))),
            0,
            0
        );
    }

    event SynthExchangeFeeUpdated(bytes32 synthKey, uint newExchangeFeeRate);
    bytes32 private constant SYNTHEXCHANGEFEEUPDATED_SIG = keccak256("SynthExchangeFeeUpdated(bytes32,uint256)");

    function emitExchangeFeeUpdated(bytes32 synthKey, uint newExchangeFeeRate) internal {
        proxy._emit(abi.encode(synthKey, newExchangeFeeRate), 1, SYNTHEXCHANGEFEEUPDATED_SIG, 0, 0, 0);
    }

    event FeePeriodDurationUpdated(uint newFeePeriodDuration);
    bytes32 private constant FEEPERIODDURATIONUPDATED_SIG = keccak256("FeePeriodDurationUpdated(uint256)");

    function emitFeePeriodDurationUpdated(uint newFeePeriodDuration) internal {
        proxy._emit(abi.encode(newFeePeriodDuration), 1, FEEPERIODDURATIONUPDATED_SIG, 0, 0, 0);
    }

    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 Security Audit

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":"uint256","name":"feePeriodId","type":"uint256"}],"name":"FeePeriodClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFeePeriodDuration","type":"uint256"}],"name":"FeePeriodDurationUpdated","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":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"debtRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtEntryIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feePeriodStartingDebtIndex","type":"uint256"}],"name":"IssuanceDebtRatioEntry","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newBeneficiary","type":"address"}],"name":"SelfDestructBeneficiaryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"selfDestructDelay","type":"uint256"}],"name":"SelfDestructInitiated","type":"event"},{"anonymous":false,"inputs":[],"name":"SelfDestructTerminated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"}],"name":"SelfDestructed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"synthKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"newExchangeFeeRate","type":"uint256"}],"name":"SynthExchangeFeeUpdated","type":"event"},{"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":true,"inputs":[],"name":"MAX_ADDRESSES_FROM_RESOLVER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_EXCHANGE_FEE_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_FEE_PERIOD_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MIN_FEE_PERIOD_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SELFDESTRUCT_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"debtRatio","type":"uint256"},{"internalType":"uint256","name":"debtEntryIndex","type":"uint256"}],"name":"appendAccountIssuanceRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"appendVestingEntry","outputs":[],"payable":false,"stateMutability":"nonpayable","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":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":"feesByPeriod","outputs":[{"internalType":"uint256[2][2]","name":"results","type":"uint256[2][2]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"synthKey","type":"bytes32"}],"name":"getExchangeFeeRateForSynth","outputs":[{"internalType":"uint256","name":"exchangeFeeRate","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":true,"inputs":[],"name":"getResolverAddressesRequired","outputs":[{"internalType":"bytes32[24]","name":"addressesRequired","type":"bytes32[24]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"feePeriodIndex","type":"uint256"},{"internalType":"uint256","name":"feePeriodId","type":"uint256"},{"internalType":"uint256","name":"startingDebtIndex","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":false,"inputs":[],"name":"initiateSelfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initiationTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"integrationProxy","outputs":[{"internalType":"contract Proxy","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isFeesClaimable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract AddressResolver","name":"_resolver","type":"address"}],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":true,"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"recentFeePeriods","outputs":[{"internalType":"uint64","name":"feePeriodId","type":"uint64"},{"internalType":"uint64","name":"startingDebtIndex","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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"selfDestructBeneficiary","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"selfDestructInitiated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32[]","name":"synthKeys","type":"bytes32[]"},{"internalType":"uint256[]","name":"exchangeFeeRates","type":"uint256[]"}],"name":"setExchangeFeeRateForSynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_feePeriodDuration","type":"uint256"}],"name":"setFeePeriodDuration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_integrationProxy","type":"address"}],"name":"setIntegrationProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","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":"contract AddressResolver","name":"_resolver","type":"address"}],"name":"setResolverAndSyncCache","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":false,"inputs":[{"internalType":"address payable","name":"_beneficiary","type":"address"}],"name":"setSelfDestructBeneficiary","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_percent","type":"uint256"}],"name":"setTargetThreshold","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":false,"inputs":[],"name":"terminateSelfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalFeesAvailable","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"}]

60806040819052631cd554d160e21b600b5562093a80601755630241ebdb60e61b81526064907384d626b2bb4d0f064067e4bf80fce7055d8f3e7b9063907af6c09060849060209060048186803b1580156200005a57600080fd5b505af41580156200006f573d6000803e3d6000fd5b505050506040513d60208110156200008657600080fd5b5051816200009057fe5b046018556040518061014001604052806b53797374656d53746174757360a01b8152602001680a6f2dce8d0cae8d2f60bb1b81526020016b466565506f6f6c537461746560a01b81526020017f466565506f6f6c457465726e616c53746f72616765000000000000000000000081526020016822bc31b430b733b2b960b91b81526020016524b9b9bab2b960d11b81526020016d53796e746865746978537461746560901b81526020016b526577617264457363726f7760a01b81526020017044656c6567617465417070726f76616c7360781b81526020017f52657761726473446973747269627574696f6e00000000000000000000000000815250601990600a6200019f929190620005a7565b50348015620001ad57600080fd5b5060405162004f6338038062004f6383398181016040526060811015620001d357600080fd5b5080516020820151604092830151835161030081019485905292939192909182919060199060189082845b815481526020019060010190808311620001fe575050505050621baf80858560006001600160a01b0316816001600160a01b0316141562000286576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1506000546001600160a01b031662000331576040805162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b604482015290519081900360640190fd5b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9181900360200190a1506000546001600160a01b0316620003d5576040805162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b604482015290519081900360640190fd5b60005460068054610100600160a81b0319166101006001600160a01b0390931692830217905560408051918252517fd5da63a0b864b315bc04128dedbc93888c8529ee6cf47ce664dc204339228c53916020908290030190a142016007556000546001600160a01b031662000485576040805162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b604482015290519081900360640190fd5b60005b6018811015620004ed576000828260188110620004a157fe5b602002015114620004de57600a828260188110620004bb57fe5b6020908102919091015182546001810184556000938452919092200155620004e4565b620004ed565b60010162000488565b5050600880546001600160a01b0319166001600160a01b039290921691909117905560016200051d60006200057b565b80546001600160401b0319166001600160401b0392909216919091179055426200054860006200057b565b80546001600160401b0392909216600160801b02600160801b600160c01b0319909216919091179055506200060a915050565b6000600c600260ff168360165401816200059157fe5b06600281106200059d57fe5b6005020192915050565b8260188101928215620005d8579160200282015b82811115620005d8578251825591602001919060010190620005bb565b50620005e6929150620005ea565b5090565b6200060791905b80821115620005e65760008155600101620005f1565b90565b614949806200061a6000396000f3fe608060405234801561001057600080fd5b50600436106103575760003560e01c806380803fff116101c8578063bd32aa4411610104578063e0e6393d116100a2578063ec5568891161007c578063ec55688914610984578063f344da671461098c578063fb1b4c7e14610994578063fd1f498d1461099c57610357565b8063e0e6393d1461096c578063e3235c9114610974578063eb1edd611461097c57610357565b8063cff2ddad116100de578063cff2ddad14610936578063d294f09314610954578063d62ae3991461095c578063d67bdd251461096457610357565b8063bd32aa4414610909578063c58aaae614610911578063c6c9d8281461091957610357565b8063a461fc8211610171578063b10090b81161014b578063b10090b814610867578063b5ddb9c7146108af578063b8225dec146108db578063bc67f832146108e357610357565b8063a461fc8214610816578063ab49848c1461081e578063ac8341931461085f57610357565b806397107d6d116101a257806397107d6d146107e05780639cb8a26a146108065780639cbdaeb61461080e57610357565b806380803fff1461078957806386645274146107a65780638da5cb5b146107d857610357565b80633278c9601161029757806353a47bb711610240578063631e14441161021a578063631e14441461072d5780636466f45e146107535780636de813f11461077957806379ba50971461078157610357565b806353a47bb7146106e3578063569249d0146106eb57806359a2f19f146106f357610357565b80633ebc457a116102715780633ebc457a1461066e5780633fcd22401461067657806346ba2d90146106db57610357565b80633278c960146105c057806333140016146105c85780633be99e6f1461064857610357565b80631627540c1161030457806322425fa4116102de57806322425fa4146104bc57806322bf55ef146104c457806328a1170d146104e15780632cce0e54146105a357610357565b80631627540c1461046857806317c70de41461048e57806320714f881461049657610357565b80630813071c116103355780630813071c146103d75780630de5861514610403578063131b0ae71461044257610357565b806304c49f2c1461035c57806304f3bcec1461037b57806307ea50cd1461039f575b600080fd5b6103796004803603602081101561037257600080fd5b50356109b9565b005b610383610b2a565b604080516001600160a01b039092168252519081900360200190f35b6103c5600480360360208110156103b557600080fd5b50356001600160a01b0316610b39565b60408051918252519081900360200190f35b6103c5600480360360408110156103ed57600080fd5b506001600160a01b038135169060200135610c1d565b6104296004803603602081101561041957600080fd5b50356001600160a01b0316610dce565b6040805192835260208301919091528051918290030190f35b6103796004803603602081101561045857600080fd5b50356001600160a01b0316610e4f565b6103796004803603602081101561047e57600080fd5b50356001600160a01b0316610eba565b6103c5610f57565b610379600480360360208110156104ac57600080fd5b50356001600160a01b0316610f5d565b6103c5611074565b610379600480360360208110156104da57600080fd5b503561107a565b610379600480360360408110156104f757600080fd5b81019060208101813564010000000081111561051257600080fd5b82018360208201111561052457600080fd5b8035906020019184602083028401116401000000008311171561054657600080fd5b91939092909160208101903564010000000081111561056457600080fd5b82018360208201111561057657600080fd5b8035906020019184602083028401116401000000008311171561059857600080fd5b509092509050611196565b610379600480360360208110156105b957600080fd5b5035611430565b6103796115cd565b6105ee600480360360208110156105de57600080fd5b50356001600160a01b0316611650565b6040516000826002835b818410156106385760208402830151604080838360005b8381101561062757818101518382015260200161060f565b5050505090500192600101926105f8565b9250505091505060405180910390f35b6103796004803603602081101561065e57600080fd5b50356001600160a01b03166118a0565b610379611a27565b6106936004803603602081101561068c57600080fd5b5035611d72565b6040805167ffffffffffffffff9889168152968816602088015294909616858501526060850192909252608084015260a083015260c082019290925290519081900360e00190f35b6103c5611e1b565b610383611e21565b6103c5611e30565b6107196004803603602081101561070957600080fd5b50356001600160a01b0316611e8b565b604080519115158252519081900360200190f35b6107196004803603602081101561074357600080fd5b50356001600160a01b0316612051565b6107196004803603602081101561076957600080fd5b50356001600160a01b0316612185565b6103c56122dc565b610379612331565b6103c56004803603602081101561079f57600080fd5b50356123ed565b610379600480360360608110156107bc57600080fd5b506001600160a01b038135169060208101359060400135612488565b6103836125ec565b610379600480360360208110156107f657600080fd5b50356001600160a01b03166125fb565b610379612698565b6103836127ea565b6103c56127f9565b610826612800565b604051808261030080838360005b8381101561084c578181015183820152602001610834565b5050505090500191505060405180910390f35b6103c561284a565b610379600480360361010081101561087e57600080fd5b5080359060208101359060408101359060608101359060808101359060a08101359060c08101359060e00135612940565b610379600480360360408110156108c557600080fd5b506001600160a01b038135169060200135612c2a565b610719612e19565b610379600480360360208110156108f957600080fd5b50356001600160a01b0316612e22565b610379612eb8565b610383612f4a565b6103c56004803603602081101561092f57600080fd5b5035612f5e565b61093e612f7c565b6040805160ff9092168252519081900360200190f35b610719612f81565b6103c5612ff3565b610383612ffa565b6103c5613009565b6103c561300f565b610383613014565b61038361302c565b6103c561303b565b6103c5613042565b610379600480360360208110156109b257600080fd5b503561304e565b6002546001600160a01b031633148015906109df57506003546001600160a01b03163314155b80156109f657506004546001600160a01b03163314155b15610a0e57600480546001600160a01b031916331790555b6000546004546001600160a01b03908116911614610a69576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b62015180811015610ac1576040805162461bcd60e51b815260206004820152601f60248201527f76616c7565203c204d494e5f4645455f504552494f445f4455524154494f4e00604482015290519081900360640190fd5b624f1a00811115610b19576040805162461bcd60e51b815260206004820152601f60248201527f76616c7565203e204d41585f4645455f504552494f445f4455524154494f4e00604482015290519081900360640190fd5b6017819055610b2781613100565b50565b6008546001600160a01b031681565b6000610b43613227565b6001600160a01b031663bdc963d87f6c6173745f6665655f7769746864726177616c000000000000000000000000008460405160200180838152602001826001600160a01b03166001600160a01b031660601b815260140192505050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610be957600080fd5b505afa158015610bfd573d6000803e3d6000fd5b505050506040513d6020811015610c1357600080fd5b505190505b919050565b600081610c71576040805162461bcd60e51b815260206004820181905260248201527f43757272656e7420706572696f64206973206e6f7420636c6f73656420796574604482015290519081900360640190fd5b60028210610cc6576040805162461bcd60e51b815260206004820152601d60248201527f4578636565647320746865204645455f504552494f445f4c454e475448000000604482015290519081900360640190fd5b610cd26001830361326b565b5468010000000000000000900467ffffffffffffffff16610cf557506000610dc8565b6000610d256001610d086001860361326b565b5468010000000000000000900467ffffffffffffffff1690613295565b9050600080610d326132f2565b6040805163694e000560e11b81526001600160a01b03898116600483015260248201879052825193169263d29c000a92604480840193919291829003018186803b158015610d7f57600080fd5b505afa158015610d93573d6000803e3d6000fd5b505050506040513d6040811015610da957600080fd5b5080516020909101519092509050610dc2838383613353565b93505050505b92915050565b600080610dd9614633565b610de284611650565b905060008060015b6002811015610e4357610e0f848260028110610e0257fe5b6020020151518490613487565b9250610e39848260028110610e2057fe5b602002015160016020020151839063ffffffff61348716565b9150600101610dea565b50909350915050915091565b6000546001600160a01b03163314610e985760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f035760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b60055481565b6000546001600160a01b03163314610fa65760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b6001600160a01b038116611001576040805162461bcd60e51b815260206004820152601c60248201527f42656e6566696369617279206d757374206e6f74206265207a65726f00000000604482015290519081900360640190fd5b600680546001600160a01b03831661010081027fffffffffffffffffffffff0000000000000000000000000000000000000000ff9092169190911790915560408051918252517fd5da63a0b864b315bc04128dedbc93888c8529ee6cf47ce664dc204339228c539181900360200190a150565b60175481565b60006110846134e8565b6001600160a01b03163314905060008061109c613549565b6001600160a01b03166316b2213f336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110f157600080fd5b505afa158015611105573d6000803e3d6000fd5b505050506040513d602081101561111b57600080fd5b505114159050818061112a5750805b6111655760405162461bcd60e51b81526004018080602001828103825260218152602001806148cf6021913960400191505060405180910390fd5b61118383611173600061326b565b600101549063ffffffff61348716565b61118d600061326b565b60010155505050565b6002546001600160a01b031633148015906111bc57506003546001600160a01b03163314155b80156111d357506004546001600160a01b03163314155b156111eb57600480546001600160a01b031916331790555b6000546004546001600160a01b03908116911614611246576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b82811461129a576040805162461bcd60e51b815260206004820152601860248201527f4172726179206c656e6774687320646f6e74206d617463680000000000000000604482015290519081900360640190fd5b60005b838110156114295767016345785d8a00008383838181106112ba57fe5b905060200201351115611314576040805162461bcd60e51b815260206004820152601e60248201527f4d41585f45584348414e47455f4645455f524154452065786365656465640000604482015290519081900360640190fd5b61131c613227565b6001600160a01b0316633562fd207f73796e74685f65786368616e67655f6665655f7261746500000000000000000087878581811061135757fe5b9050602002013560405160200180838152602001828152602001925050506040516020818303038152906040528051906020012085858581811061139757fe5b905060200201356040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156113db57600080fd5b505af11580156113ef573d6000803e3d6000fd5b5050505061142185858381811061140257fe5b9050602002013584848481811061141557fe5b905060200201356135aa565b60010161129d565b5050505050565b6002546001600160a01b0316331480159061145657506003546001600160a01b03163314155b801561146d57506004546001600160a01b03163314155b1561148557600480546001600160a01b031916331790555b6000546004546001600160a01b039081169116146114e0576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b6032811115611536576040805162461bcd60e51b815260206004820152601260248201527f5468726573686f6c6420746f6f20686967680000000000000000000000000000604482015290519081900360640190fd5b6115c760646115bb7384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561158257600080fd5b505af4158015611596573d6000803e3d6000fd5b505050506040513d60208110156115ac57600080fd5b5051849063ffffffff6136c316565b9063ffffffff61371c16565b60185550565b6000546001600160a01b031633146116165760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600060058190556006805460ff191690556040517f6adcc7125002935e0aa31697538ebbd65cfddf20431eb6ecdcfc3e238bfd082c9190a1565b611658614633565b60008060006116656132f2565b604080517fb326f84e0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015260006024830152825193945084169263b326f84e92604480840193919291829003018186803b1580156116ce57600080fd5b505afa1580156116e2573d6000803e3d6000fd5b505050506040513d60408110156116f857600080fd5b508051602090910151909350915081158015611712575082155b1561172a5761171f614633565b9350610c1892505050565b60008061173960008686613786565b875182905287516020018190529092509050600061175688610b39565b905060015b801561189457600019810160006117718261326b565b5468010000000000000000900467ffffffffffffffff16905080158015906117ab575061179d8361326b565b5467ffffffffffffffff1684105b156118895760006117c382600163ffffffff61329516565b6040805163694e000560e11b81526001600160a01b038f811660048301526024820184905282519394508b169263d29c000a92604480840193919291829003018186803b15801561181357600080fd5b505afa158015611827573d6000803e3d6000fd5b505050506040513d604081101561183d57600080fd5b508051602090910151909a509850611856848b8b613786565b9097509550868b856002811061186857fe5b602002015152858b856002811061187b57fe5b602002015160016020020152505b50506000190161175b565b50505050505050919050565b6000546001600160a01b031633146118e95760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600880546001600160a01b0319166001600160a01b03831617905560005b600a54811015611a23576000600a828154811061192057fe5b60009182526020918290200154600854604080517fdacb2d010000000000000000000000000000000000000000000000000000000081526004810184905260248101829052601760448201527f5265736f6c766572206d697373696e6720746172676574000000000000000000606482015290519294506001600160a01b039091169263dacb2d0192608480840193829003018186803b1580156119c357600080fd5b505afa1580156119d7573d6000803e3d6000fd5b505050506040513d60208110156119ed57600080fd5b505160009182526009602052604090912080546001600160a01b0319166001600160a01b03909216919091179055600101611907565b5050565b6017544203611a36600061326b565b54600160801b900467ffffffffffffffff161115611a9b576040805162461bcd60e51b815260206004820152601d60248201527f546f6f206561726c7920746f20636c6f73652066656520706572696f64000000604482015290519081900360640190fd5b611aa3613828565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015611adb57600080fd5b505afa158015611aef573d6000803e3d6000fd5b5060009250611b01915082905061326b565b90506000611b0f600161326b565b9050611b408260010154611b348360020154846001015461329590919063ffffffff16565b9063ffffffff61348716565b611b4a600061326b565b60010155600380830154600483015491830154611b7192611b34919063ffffffff61329516565b611b7b600061326b565b60030155601654611bb890600290611bac90600190611ba0908463ffffffff61348716565b9063ffffffff61329516565b9063ffffffff61388916565b6016819055600c9060028110611bca57fe5b6005020180547fffffffffffffffff000000000000000000000000000000000000000000000000168155600060018083018290556002830182905560038301829055600490920155611c3690611c1f8161326b565b5467ffffffffffffffff169063ffffffff61348716565b611c40600061326b565b805467ffffffffffffffff191667ffffffffffffffff92909216919091179055611c686138ee565b6001600160a01b031663cd92eba96040518163ffffffff1660e01b815260040160206040518083038186803b158015611ca057600080fd5b505afa158015611cb4573d6000803e3d6000fd5b505050506040513d6020811015611cca57600080fd5b5051611cd6600061326b565b805467ffffffffffffffff9290921668010000000000000000026fffffffffffffffff00000000000000001990921691909117905542611d16600061326b565b805467ffffffffffffffff92909216600160801b027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff909216919091179055611a23611d62600161326b565b5467ffffffffffffffff1661394f565b6000806000806000806000611d85614660565b611d8e8961326b565b6040805160e081018252825467ffffffffffffffff808216808452680100000000000000008304821660208501819052600160801b909304909116938301849052600185015460608401819052600286015460808501819052600387015460a0860181905260049097015460c0909501859052919f929e50939c50929a5091985091965090945092505050565b60075481565b6001546001600160a01b031681565b60008060015b6002811015611e8557611e5c611e4b8261326b565b60010154839063ffffffff61348716565b9150611e7b611e6a8261326b565b60020154839063ffffffff61329516565b9150600101611e36565b50905090565b600080611e96613549565b6001600160a01b031663a311c7c2846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611eeb57600080fd5b505afa158015611eff573d6000803e3d6000fd5b505050506040513d6020811015611f1557600080fd5b505190506000611f236138ee565b6001600160a01b031663b410a0346040518163ffffffff1660e01b815260040160206040518083038186803b158015611f5b57600080fd5b505afa158015611f6f573d6000803e3d6000fd5b505050506040513d6020811015611f8557600080fd5b5051905080821015611f9c57600192505050610c18565b60006120306120236018547384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611feb57600080fd5b505af4158015611fff573d6000803e3d6000fd5b505050506040513d602081101561201557600080fd5b50519063ffffffff61348716565b839063ffffffff613a3816565b9050808311156120465760009350505050610c18565b506001949350505050565b6008546000906001600160a01b0383811691161461207157506000610c18565b60005b600a5481101561217c576000600a828154811061208d57fe5b6000918252602080832090910154808352600982526040928390205460085484517f21f8a7210000000000000000000000000000000000000000000000000000000081526004810184905294519295506001600160a01b03918216949116926321f8a72192602480840193829003018186803b15801561210c57600080fd5b505afa158015612120573d6000803e3d6000fd5b505050506040513d602081101561213657600080fd5b50516001600160a01b031614158061216357506000818152600960205260409020546001600160a01b0316155b1561217357600092505050610c18565b50600101612074565b50600192915050565b6002546000906001600160a01b031633148015906121ae57506003546001600160a01b03163314155b80156121c557506004546001600160a01b03163314155b156121dd57600480546001600160a01b031916331790555b6121e5613a62565b60048054604080517f21f4ae570000000000000000000000000000000000000000000000000000000081526001600160a01b038781169482019490945291831660248301525192909116916321f4ae5791604480820192602092909190829003018186803b15801561225657600080fd5b505afa15801561226a573d6000803e3d6000fd5b505050506040513d602081101561228057600080fd5b50516122d3576040805162461bcd60e51b815260206004820152601f60248201527f4e6f7420617070726f76656420746f20636c61696d206f6e20626568616c6600604482015290519081900360640190fd5b610dc882613aa6565b60008060015b6002811015611e85576123086122f78261326b565b60030154839063ffffffff61348716565b91506123276123168261326b565b60040154839063ffffffff61329516565b91506001016122e2565b6001546001600160a01b0316331461237a5760405162461bcd60e51b81526004018080602001828103825260358152602001806146f96035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60006123f7613227565b6001600160a01b031663bdc963d87f73796e74685f65786368616e67655f6665655f72617465000000000000000000846040516020018083815260200182815260200192505050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610be957600080fd5b612490613c24565b6001600160a01b0316336001600160a01b0316146124f5576040805162461bcd60e51b815260206004820152601f60248201527f466565506f6f6c3a204f6e6c792049737375657220417574686f726973656400604482015290519081900360640190fd5b6124fd6132f2565b6001600160a01b03166394e1a448848484612518600061326b565b54604080517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526001600160a01b0390951660048601526024850193909352604484019190915267ffffffffffffffff6801000000000000000090910416606483015251608480830192600092919082900301818387803b1580156125a357600080fd5b505af11580156125b7573d6000803e3d6000fd5b505050506125e78383836125cb600061326b565b5468010000000000000000900467ffffffffffffffff16613c85565b505050565b6000546001600160a01b031681565b6000546001600160a01b031633146126445760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9181900360200190a150565b6000546001600160a01b031633146126e15760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b60065460ff16612738576040805162461bcd60e51b815260206004820152601f60248201527f53656c66204465737472756374206e6f742079657420696e6974696174656400604482015290519081900360640190fd5b426224ea006005540110612793576040805162461bcd60e51b815260206004820152601b60248201527f53656c662064657374727563742064656c6179206e6f74206d65740000000000604482015290519081900360640190fd5b600654604080516101009092046001600160a01b03168252517f8a09e1677ced846cb537dc2b172043bd05a1a81ad7e0033a7ef8ba762df990b7916020908290030190a160065461010090046001600160a01b0316ff5b6003546001600160a01b031681565b6224ea0081565b6128086146bb565b60005b600a5481101561284657600a818154811061282257fe5b906000526020600020015482826018811061283957fe5b602002015260010161280b565b5090565b6000806128556138ee565b6001600160a01b031663b410a0346040518163ffffffff1660e01b815260040160206040518083038186803b15801561288d57600080fd5b505afa1580156128a1573d6000803e3d6000fd5b505050506040513d60208110156128b757600080fd5b5051601854604080517f907af6c0000000000000000000000000000000000000000000000000000000008152905192935061293a9261292d92917384d626b2bb4d0f064067e4bf80fce7055d8f3e7b9163907af6c091600480820192602092909190829003018186803b158015611feb57600080fd5b829063ffffffff613a3816565b91505090565b6002546001600160a01b0316331480159061296657506003546001600160a01b03163314155b801561297d57506004546001600160a01b03163314155b1561299557600480546001600160a01b031916331790555b6000546004546001600160a01b039081169116146129f0576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b6007544210612a305760405162461bcd60e51b815260040180806020018281038252602981526020018061487e6029913960400191505060405180910390fd5b612a386138ee565b6001600160a01b031663cd92eba96040518163ffffffff1660e01b815260040160206040518083038186803b158015612a7057600080fd5b505afa158015612a84573d6000803e3d6000fd5b505050506040513d6020811015612a9a57600080fd5b5051861115612af0576040805162461bcd60e51b815260206004820152601660248201527f43616e6e6f7420696d706f727420626164206461746100000000000000000000604482015290519081900360640190fd5b6040518060e001604052808867ffffffffffffffff1681526020018767ffffffffffffffff1681526020018667ffffffffffffffff16815260200185815260200184815260200183815260200182815250600c612b60600260ff16611bac8c60165461348790919063ffffffff16565b60028110612b6a57fe5b82516005919091029190910180546020840151604085015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff000000000000000019166801000000000000000091851691909102177fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16600160801b9390911692909202919091178155606082015160018201556080820151600282015560a0820151600382015560c0909101516004909101555050505050505050565b6002546001600160a01b03163314801590612c5057506003546001600160a01b03163314155b8015612c6757506004546001600160a01b03163314155b15612c7f57600480546001600160a01b031916331790555b6000546004546001600160a01b03908116911614612cda576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b612ce2613549565b6004546001600160a01b03918216916323b872dd9116612d00613dcc565b846040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015612d6957600080fd5b505af1158015612d7d573d6000803e3d6000fd5b505050506040513d6020811015612d9357600080fd5b50612d9e9050613dcc565b6001600160a01b031663b5ddb9c783836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612dfd57600080fd5b505af1158015612e11573d6000803e3d6000fd5b505050505050565b60065460ff1681565b6002546001600160a01b0316331480612e4557506003546001600160a01b031633145b612e96576040805162461bcd60e51b815260206004820152601760248201527f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000604482015290519081900360640190fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314612f015760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b426005556006805460ff19166001179055604080516224ea00815290517fcbd94ca75b8dc45c9d80c77e851670e78843c0d75180cb81db3e2158228fa9a69181900360200190a1565b60065461010090046001600160a01b031681565b600a8181548110612f6b57fe5b600091825260209091200154905081565b600281565b6002546000906001600160a01b03163314801590612faa57506003546001600160a01b03163314155b8015612fc157506004546001600160a01b03163314155b15612fd957600480546001600160a01b031916331790555b600454612fee906001600160a01b0316613aa6565b905090565b6201518081565b6004546001600160a01b031681565b60185481565b601881565b73feefeefeefeefeefeefeefeefeefeefeefeefeef81565b6002546001600160a01b031681565b624f1a0081565b67016345785d8a000081565b6000613058613e2d565b6004549091506001600160a01b038083169116148061307f5750336001600160a01b038216145b6130d0576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f742072657761726473417574686f726974790000604482015290519081900360640190fd5b6130ee826130de600061326b565b600301549063ffffffff61348716565b6130f8600061326b565b600301555050565b60025460408051602080820185905282518083039091018152908201918290526001600160a01b039092169163907dff97916001908060216147ea82396021019050604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156131c25781810151838201526020016131aa565b50505050905090810190601f1680156131ef5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b15801561321357600080fd5b505af1158015611429573d6000803e3d6000fd5b6000612fee7f466565506f6f6c457465726e616c53746f7261676500000000000000000000006040518060600160405280602581526020016148f060259139613e6d565b6000600c600260ff1683601654018161328057fe5b066002811061328b57fe5b6005020192915050565b6000828211156132ec576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000612fee7f466565506f6f6c537461746500000000000000000000000000000000000000006040518060400160405280601c81526020017f4d697373696e6720466565506f6f6c5374617465206164647265737300000000815250613e6d565b60008061335e6138ee565b9050600061347d85613471846001600160a01b03166308d95cd5886040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d60208110156133d757600080fd5b5051604080517f08d95cd5000000000000000000000000000000000000000000000000000000008152600481018c905290516001600160a01b038816916308d95cd5916024808301926020929190829003018186803b15801561343957600080fd5b505afa15801561344d573d6000803e3d6000fd5b505050506040513d602081101561346357600080fd5b50519063ffffffff613f1716565b9063ffffffff613f3016565b9695505050505050565b6000828201838110156134e1576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000612fee7f45786368616e67657200000000000000000000000000000000000000000000006040518060400160405280601981526020017f4d697373696e672045786368616e676572206164647265737300000000000000815250613e6d565b6000612fee7f53796e74686574697800000000000000000000000000000000000000000000006040518060400160405280601981526020017f4d697373696e672053796e746865746978206164647265737300000000000000815250613e6d565b60025460408051602081018590528082018490528151808203830181526060909101918290526001600160a01b039092169163907dff97916001908060286148a782396028019050604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b8381101561367257818101518382015260200161365a565b50505050905090810190601f16801561369f5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b158015612dfd57600080fd5b6000826136d257506000610dc8565b828202828482816136df57fe5b04146134e15760405162461bcd60e51b815260040180806020018281038252602181526020018061485d6021913960400191505060405180910390fd5b6000808211613772576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b600082848161377d57fe5b04949350505050565b6000808361379957506000905080613820565b8385156137c45760006137b36001610d0860018a0361326b565b90506137c0818787613353565b9150505b60006137e3826137d38961326b565b600101549063ffffffff613a3816565b90506000613804836137f48a61326b565b600301549063ffffffff613a3816565b905061380f82613f49565b61381882613f49565b945094505050505b935093915050565b6000612fee7f53797374656d53746174757300000000000000000000000000000000000000006040518060400160405280601c81526020017f4d697373696e672053797374656d537461747573206164647265737300000000815250613e6d565b6000816138dd576040805162461bcd60e51b815260206004820152601860248201527f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000604482015290519081900360640190fd5b8183816138e657fe5b069392505050565b6000612fee7f53796e74686574697853746174650000000000000000000000000000000000006040518060400160405280601e81526020017f4d697373696e672053796e746865746978537461746520616464726573730000815250613e6d565b6002546040805160208082018590528251808303820181528284018085527f466565506572696f64436c6f7365642875696e74323536290000000000000000905292519182900360580182207f907dff97000000000000000000000000000000000000000000000000000000008352600160248401819052604484018290526000606485018190526084850181905260a4850181905260c060048601908152865160c487015286516001600160a01b039098169763907dff979796939592938493849392839260e401918a019080838388838110156131c25781810151838201526020016131aa565b6000670de0b6b3a7640000613a53848463ffffffff6136c316565b81613a5a57fe5b049392505050565b6000612fee7f44656c6567617465417070726f76616c7300000000000000000000000000000060405180606001604052806021815260200161475260219139613e6d565b6000613ab0613828565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015613ae857600080fd5b505afa158015613afc573d6000803e3d6000fd5b506000925082915081905080613b1186611e8b565b613b62576040805162461bcd60e51b815260206004820152601f60248201527f432d526174696f2062656c6f772070656e616c7479207468726573686f6c6400604482015290519081900360640190fd5b613b6b86610dce565b909250905081151580613b7e5750600081115b613bb95760405162461bcd60e51b81526004018080602001828103825260408152602001806147aa6040913960400191505060405180910390fd5b613bd786613bc7600161326b565b5467ffffffffffffffff16613f6b565b8115613bf257613be682614023565b9250613bf286846140f7565b8015613c0d57613c01816142dc565b9350613c0d86856143b6565b613c188684866144ad565b50600195945050505050565b6000612fee7f49737375657200000000000000000000000000000000000000000000000000006040518060400160405280601681526020017f4d697373696e6720497373756572206164647265737300000000000000000000815250613e6d565b6002805460408051602081018790528082018690526060808201869052825180830390910181526080909101918290526001600160a01b039092169263907dff979291806037614773823960370190506040518091039020886001600160a01b031660001b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015613d5d578181015183820152602001613d45565b50505050905090810190601f168015613d8a5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b158015613dae57600080fd5b505af1158015613dc2573d6000803e3d6000fd5b5050505050505050565b6000612fee7f526577617264457363726f7700000000000000000000000000000000000000006040518060400160405280601c81526020017f4d697373696e6720526577617264457363726f77206164647265737300000000815250613e6d565b6000612fee7f52657761726473446973747269627574696f6e0000000000000000000000000060405180606001604052806023815260200161483a602391395b6000828152600960205260408120546001600160a01b03168281613f0f5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613ed4578181015183820152602001613ebc565b50505050905090810190601f168015613f015780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b60006134e183836b033b2e3c9fd0803ce80000006145d0565b60006134e183836b033b2e3c9fd0803ce8000000614608565b60006305f5e10082046005600a820610613f6157600a015b600a900492915050565b613f73613227565b6001600160a01b0316633562fd207f6c6173745f6665655f7769746864726177616c000000000000000000000000008460405160200180838152602001826001600160a01b03166001600160a01b031660601b81526014019250505060405160208183030381529060405280519060200120836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015612dfd57600080fd5b6000818160015b6002811015613f0f57600061403e8261326b565b6002015490506000614063826140538561326b565b600101549063ffffffff61329516565b905080156140ec57600085821061407a578561407c565b815b905061408e838263ffffffff61348716565b6140978561326b565b600201556140ab868263ffffffff61329516565b95506140bd858263ffffffff61348716565b9450856140d257849650505050505050610c18565b831580156140e05750600086115b156140ea57600095505b505b50506000190161402a565b816001600160a01b03811673feefeefeefeefeefeefeefeefeefeefeefeefeef141561416a576040805162461bcd60e51b815260206004820152601760248201527f4665652061646472657373206e6f7420616c6c6f776564000000000000000000604482015290519081900360640190fd5b6000614174613549565b6001600160a01b03166332608039600b546040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156141b957600080fd5b505afa1580156141cd573d6000803e3d6000fd5b505050506040513d60208110156141e357600080fd5b5051604080517f9dc29fac00000000000000000000000000000000000000000000000000000000815273feefeefeefeefeefeefeefeefeefeefeefeefeef60048201526024810186905290519192506001600160a01b03831691639dc29fac9160448082019260009290919082900301818387803b15801561426457600080fd5b505af1158015614278573d6000803e3d6000fd5b50505050806001600160a01b031663867904b485856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613dae57600080fd5b6000818160015b6002811015613f0f5760006143176142fa8361326b565b600401546143078461326b565b600301549063ffffffff61329516565b905080156143ac57600084821061432e5784614330565b815b905061434f8161433f8561326b565b600401549063ffffffff61348716565b6143588461326b565b6004015561436c858263ffffffff61329516565b945061437e848263ffffffff61348716565b935084614392578395505050505050610c18565b821580156143a05750600085115b156143aa57600094505b505b50600019016142e3565b816001600160a01b03811673feefeefeefeefeefeefeefeefeefeefeefeefeef1415614429576040805162461bcd60e51b815260206004820152601760248201527f4665652061646472657373206e6f7420616c6c6f776564000000000000000000604482015290519081900360640190fd5b614431613dcc565b6001600160a01b031663b5ddb9c784846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561449057600080fd5b505af11580156144a4573d6000803e3d6000fd5b50505050505050565b600254604080516001600160a01b0386811660208301528183018690526060808301869052835180840390910181526080909201928390529092169163907dff979160019080602461472e82396024019050604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b8381101561457f578181015183820152602001614567565b50505050905090810190601f1680156145ac5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b15801561449057600080fd5b6000806145ea846115bb87600a870263ffffffff6136c316565b90506005600a825b06106145fc57600a015b600a9004949350505050565b600080600a830461461f868663ffffffff6136c316565b8161462657fe5b0490506005600a826145f2565b60405180604001604052806002905b61464a6146da565b8152602001906001900390816146425790505090565b6040518060e00160405280600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600081526020016000815260200160008152602001600081525090565b6040518061030001604052806018906020820280388339509192915050565b6040518060400160405280600290602082028038833950919291505056fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e65727368697046656573436c61696d656428616464726573732c75696e743235362c75696e74323536294d697373696e672044656c6567617465417070726f76616c73206164647265737349737375616e636544656274526174696f456e74727928616464726573732c75696e743235362c75696e743235362c75696e74323536294e6f2066656573206f72207265776172647320617661696c61626c6520666f7220706572696f642c206f72206665657320616c726561647920636c61696d6564466565506572696f644475726174696f6e557064617465642875696e74323536294f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e4d697373696e672052657761726473446973747269627574696f6e2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616e206f6e6c7920706572666f726d207468697320616374696f6e20647572696e6720736574757053796e746845786368616e67654665655570646174656428627974657333322c75696e74323536294f6e6c792045786368616e6765722c2053796e74687320417574686f72697365644d697373696e6720466565506f6f6c457465726e616c53746f726167652061646472657373a265627a7a72315820df3d94c204228d52bdeab83f2e8f4a1142a185790336acf62f2437c0d7be5c7264736f6c63430005100032000000000000000000000000b440dd674e1243644791a4adfe3a2abb0a92d309000000000000000000000000de910777c787903f78c89e7a0bf7f4c435cbb1fe000000000000000000000000fbb6526ed92da8915d4843a86166020d0b7baad0

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103575760003560e01c806380803fff116101c8578063bd32aa4411610104578063e0e6393d116100a2578063ec5568891161007c578063ec55688914610984578063f344da671461098c578063fb1b4c7e14610994578063fd1f498d1461099c57610357565b8063e0e6393d1461096c578063e3235c9114610974578063eb1edd611461097c57610357565b8063cff2ddad116100de578063cff2ddad14610936578063d294f09314610954578063d62ae3991461095c578063d67bdd251461096457610357565b8063bd32aa4414610909578063c58aaae614610911578063c6c9d8281461091957610357565b8063a461fc8211610171578063b10090b81161014b578063b10090b814610867578063b5ddb9c7146108af578063b8225dec146108db578063bc67f832146108e357610357565b8063a461fc8214610816578063ab49848c1461081e578063ac8341931461085f57610357565b806397107d6d116101a257806397107d6d146107e05780639cb8a26a146108065780639cbdaeb61461080e57610357565b806380803fff1461078957806386645274146107a65780638da5cb5b146107d857610357565b80633278c9601161029757806353a47bb711610240578063631e14441161021a578063631e14441461072d5780636466f45e146107535780636de813f11461077957806379ba50971461078157610357565b806353a47bb7146106e3578063569249d0146106eb57806359a2f19f146106f357610357565b80633ebc457a116102715780633ebc457a1461066e5780633fcd22401461067657806346ba2d90146106db57610357565b80633278c960146105c057806333140016146105c85780633be99e6f1461064857610357565b80631627540c1161030457806322425fa4116102de57806322425fa4146104bc57806322bf55ef146104c457806328a1170d146104e15780632cce0e54146105a357610357565b80631627540c1461046857806317c70de41461048e57806320714f881461049657610357565b80630813071c116103355780630813071c146103d75780630de5861514610403578063131b0ae71461044257610357565b806304c49f2c1461035c57806304f3bcec1461037b57806307ea50cd1461039f575b600080fd5b6103796004803603602081101561037257600080fd5b50356109b9565b005b610383610b2a565b604080516001600160a01b039092168252519081900360200190f35b6103c5600480360360208110156103b557600080fd5b50356001600160a01b0316610b39565b60408051918252519081900360200190f35b6103c5600480360360408110156103ed57600080fd5b506001600160a01b038135169060200135610c1d565b6104296004803603602081101561041957600080fd5b50356001600160a01b0316610dce565b6040805192835260208301919091528051918290030190f35b6103796004803603602081101561045857600080fd5b50356001600160a01b0316610e4f565b6103796004803603602081101561047e57600080fd5b50356001600160a01b0316610eba565b6103c5610f57565b610379600480360360208110156104ac57600080fd5b50356001600160a01b0316610f5d565b6103c5611074565b610379600480360360208110156104da57600080fd5b503561107a565b610379600480360360408110156104f757600080fd5b81019060208101813564010000000081111561051257600080fd5b82018360208201111561052457600080fd5b8035906020019184602083028401116401000000008311171561054657600080fd5b91939092909160208101903564010000000081111561056457600080fd5b82018360208201111561057657600080fd5b8035906020019184602083028401116401000000008311171561059857600080fd5b509092509050611196565b610379600480360360208110156105b957600080fd5b5035611430565b6103796115cd565b6105ee600480360360208110156105de57600080fd5b50356001600160a01b0316611650565b6040516000826002835b818410156106385760208402830151604080838360005b8381101561062757818101518382015260200161060f565b5050505090500192600101926105f8565b9250505091505060405180910390f35b6103796004803603602081101561065e57600080fd5b50356001600160a01b03166118a0565b610379611a27565b6106936004803603602081101561068c57600080fd5b5035611d72565b6040805167ffffffffffffffff9889168152968816602088015294909616858501526060850192909252608084015260a083015260c082019290925290519081900360e00190f35b6103c5611e1b565b610383611e21565b6103c5611e30565b6107196004803603602081101561070957600080fd5b50356001600160a01b0316611e8b565b604080519115158252519081900360200190f35b6107196004803603602081101561074357600080fd5b50356001600160a01b0316612051565b6107196004803603602081101561076957600080fd5b50356001600160a01b0316612185565b6103c56122dc565b610379612331565b6103c56004803603602081101561079f57600080fd5b50356123ed565b610379600480360360608110156107bc57600080fd5b506001600160a01b038135169060208101359060400135612488565b6103836125ec565b610379600480360360208110156107f657600080fd5b50356001600160a01b03166125fb565b610379612698565b6103836127ea565b6103c56127f9565b610826612800565b604051808261030080838360005b8381101561084c578181015183820152602001610834565b5050505090500191505060405180910390f35b6103c561284a565b610379600480360361010081101561087e57600080fd5b5080359060208101359060408101359060608101359060808101359060a08101359060c08101359060e00135612940565b610379600480360360408110156108c557600080fd5b506001600160a01b038135169060200135612c2a565b610719612e19565b610379600480360360208110156108f957600080fd5b50356001600160a01b0316612e22565b610379612eb8565b610383612f4a565b6103c56004803603602081101561092f57600080fd5b5035612f5e565b61093e612f7c565b6040805160ff9092168252519081900360200190f35b610719612f81565b6103c5612ff3565b610383612ffa565b6103c5613009565b6103c561300f565b610383613014565b61038361302c565b6103c561303b565b6103c5613042565b610379600480360360208110156109b257600080fd5b503561304e565b6002546001600160a01b031633148015906109df57506003546001600160a01b03163314155b80156109f657506004546001600160a01b03163314155b15610a0e57600480546001600160a01b031916331790555b6000546004546001600160a01b03908116911614610a69576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b62015180811015610ac1576040805162461bcd60e51b815260206004820152601f60248201527f76616c7565203c204d494e5f4645455f504552494f445f4455524154494f4e00604482015290519081900360640190fd5b624f1a00811115610b19576040805162461bcd60e51b815260206004820152601f60248201527f76616c7565203e204d41585f4645455f504552494f445f4455524154494f4e00604482015290519081900360640190fd5b6017819055610b2781613100565b50565b6008546001600160a01b031681565b6000610b43613227565b6001600160a01b031663bdc963d87f6c6173745f6665655f7769746864726177616c000000000000000000000000008460405160200180838152602001826001600160a01b03166001600160a01b031660601b815260140192505050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610be957600080fd5b505afa158015610bfd573d6000803e3d6000fd5b505050506040513d6020811015610c1357600080fd5b505190505b919050565b600081610c71576040805162461bcd60e51b815260206004820181905260248201527f43757272656e7420706572696f64206973206e6f7420636c6f73656420796574604482015290519081900360640190fd5b60028210610cc6576040805162461bcd60e51b815260206004820152601d60248201527f4578636565647320746865204645455f504552494f445f4c454e475448000000604482015290519081900360640190fd5b610cd26001830361326b565b5468010000000000000000900467ffffffffffffffff16610cf557506000610dc8565b6000610d256001610d086001860361326b565b5468010000000000000000900467ffffffffffffffff1690613295565b9050600080610d326132f2565b6040805163694e000560e11b81526001600160a01b03898116600483015260248201879052825193169263d29c000a92604480840193919291829003018186803b158015610d7f57600080fd5b505afa158015610d93573d6000803e3d6000fd5b505050506040513d6040811015610da957600080fd5b5080516020909101519092509050610dc2838383613353565b93505050505b92915050565b600080610dd9614633565b610de284611650565b905060008060015b6002811015610e4357610e0f848260028110610e0257fe5b6020020151518490613487565b9250610e39848260028110610e2057fe5b602002015160016020020151839063ffffffff61348716565b9150600101610dea565b50909350915050915091565b6000546001600160a01b03163314610e985760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610f035760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b60055481565b6000546001600160a01b03163314610fa65760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b6001600160a01b038116611001576040805162461bcd60e51b815260206004820152601c60248201527f42656e6566696369617279206d757374206e6f74206265207a65726f00000000604482015290519081900360640190fd5b600680546001600160a01b03831661010081027fffffffffffffffffffffff0000000000000000000000000000000000000000ff9092169190911790915560408051918252517fd5da63a0b864b315bc04128dedbc93888c8529ee6cf47ce664dc204339228c539181900360200190a150565b60175481565b60006110846134e8565b6001600160a01b03163314905060008061109c613549565b6001600160a01b03166316b2213f336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110f157600080fd5b505afa158015611105573d6000803e3d6000fd5b505050506040513d602081101561111b57600080fd5b505114159050818061112a5750805b6111655760405162461bcd60e51b81526004018080602001828103825260218152602001806148cf6021913960400191505060405180910390fd5b61118383611173600061326b565b600101549063ffffffff61348716565b61118d600061326b565b60010155505050565b6002546001600160a01b031633148015906111bc57506003546001600160a01b03163314155b80156111d357506004546001600160a01b03163314155b156111eb57600480546001600160a01b031916331790555b6000546004546001600160a01b03908116911614611246576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b82811461129a576040805162461bcd60e51b815260206004820152601860248201527f4172726179206c656e6774687320646f6e74206d617463680000000000000000604482015290519081900360640190fd5b60005b838110156114295767016345785d8a00008383838181106112ba57fe5b905060200201351115611314576040805162461bcd60e51b815260206004820152601e60248201527f4d41585f45584348414e47455f4645455f524154452065786365656465640000604482015290519081900360640190fd5b61131c613227565b6001600160a01b0316633562fd207f73796e74685f65786368616e67655f6665655f7261746500000000000000000087878581811061135757fe5b9050602002013560405160200180838152602001828152602001925050506040516020818303038152906040528051906020012085858581811061139757fe5b905060200201356040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156113db57600080fd5b505af11580156113ef573d6000803e3d6000fd5b5050505061142185858381811061140257fe5b9050602002013584848481811061141557fe5b905060200201356135aa565b60010161129d565b5050505050565b6002546001600160a01b0316331480159061145657506003546001600160a01b03163314155b801561146d57506004546001600160a01b03163314155b1561148557600480546001600160a01b031916331790555b6000546004546001600160a01b039081169116146114e0576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b6032811115611536576040805162461bcd60e51b815260206004820152601260248201527f5468726573686f6c6420746f6f20686967680000000000000000000000000000604482015290519081900360640190fd5b6115c760646115bb7384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561158257600080fd5b505af4158015611596573d6000803e3d6000fd5b505050506040513d60208110156115ac57600080fd5b5051849063ffffffff6136c316565b9063ffffffff61371c16565b60185550565b6000546001600160a01b031633146116165760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600060058190556006805460ff191690556040517f6adcc7125002935e0aa31697538ebbd65cfddf20431eb6ecdcfc3e238bfd082c9190a1565b611658614633565b60008060006116656132f2565b604080517fb326f84e0000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015260006024830152825193945084169263b326f84e92604480840193919291829003018186803b1580156116ce57600080fd5b505afa1580156116e2573d6000803e3d6000fd5b505050506040513d60408110156116f857600080fd5b508051602090910151909350915081158015611712575082155b1561172a5761171f614633565b9350610c1892505050565b60008061173960008686613786565b875182905287516020018190529092509050600061175688610b39565b905060015b801561189457600019810160006117718261326b565b5468010000000000000000900467ffffffffffffffff16905080158015906117ab575061179d8361326b565b5467ffffffffffffffff1684105b156118895760006117c382600163ffffffff61329516565b6040805163694e000560e11b81526001600160a01b038f811660048301526024820184905282519394508b169263d29c000a92604480840193919291829003018186803b15801561181357600080fd5b505afa158015611827573d6000803e3d6000fd5b505050506040513d604081101561183d57600080fd5b508051602090910151909a509850611856848b8b613786565b9097509550868b856002811061186857fe5b602002015152858b856002811061187b57fe5b602002015160016020020152505b50506000190161175b565b50505050505050919050565b6000546001600160a01b031633146118e95760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600880546001600160a01b0319166001600160a01b03831617905560005b600a54811015611a23576000600a828154811061192057fe5b60009182526020918290200154600854604080517fdacb2d010000000000000000000000000000000000000000000000000000000081526004810184905260248101829052601760448201527f5265736f6c766572206d697373696e6720746172676574000000000000000000606482015290519294506001600160a01b039091169263dacb2d0192608480840193829003018186803b1580156119c357600080fd5b505afa1580156119d7573d6000803e3d6000fd5b505050506040513d60208110156119ed57600080fd5b505160009182526009602052604090912080546001600160a01b0319166001600160a01b03909216919091179055600101611907565b5050565b6017544203611a36600061326b565b54600160801b900467ffffffffffffffff161115611a9b576040805162461bcd60e51b815260206004820152601d60248201527f546f6f206561726c7920746f20636c6f73652066656520706572696f64000000604482015290519081900360640190fd5b611aa3613828565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015611adb57600080fd5b505afa158015611aef573d6000803e3d6000fd5b5060009250611b01915082905061326b565b90506000611b0f600161326b565b9050611b408260010154611b348360020154846001015461329590919063ffffffff16565b9063ffffffff61348716565b611b4a600061326b565b60010155600380830154600483015491830154611b7192611b34919063ffffffff61329516565b611b7b600061326b565b60030155601654611bb890600290611bac90600190611ba0908463ffffffff61348716565b9063ffffffff61329516565b9063ffffffff61388916565b6016819055600c9060028110611bca57fe5b6005020180547fffffffffffffffff000000000000000000000000000000000000000000000000168155600060018083018290556002830182905560038301829055600490920155611c3690611c1f8161326b565b5467ffffffffffffffff169063ffffffff61348716565b611c40600061326b565b805467ffffffffffffffff191667ffffffffffffffff92909216919091179055611c686138ee565b6001600160a01b031663cd92eba96040518163ffffffff1660e01b815260040160206040518083038186803b158015611ca057600080fd5b505afa158015611cb4573d6000803e3d6000fd5b505050506040513d6020811015611cca57600080fd5b5051611cd6600061326b565b805467ffffffffffffffff9290921668010000000000000000026fffffffffffffffff00000000000000001990921691909117905542611d16600061326b565b805467ffffffffffffffff92909216600160801b027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff909216919091179055611a23611d62600161326b565b5467ffffffffffffffff1661394f565b6000806000806000806000611d85614660565b611d8e8961326b565b6040805160e081018252825467ffffffffffffffff808216808452680100000000000000008304821660208501819052600160801b909304909116938301849052600185015460608401819052600286015460808501819052600387015460a0860181905260049097015460c0909501859052919f929e50939c50929a5091985091965090945092505050565b60075481565b6001546001600160a01b031681565b60008060015b6002811015611e8557611e5c611e4b8261326b565b60010154839063ffffffff61348716565b9150611e7b611e6a8261326b565b60020154839063ffffffff61329516565b9150600101611e36565b50905090565b600080611e96613549565b6001600160a01b031663a311c7c2846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611eeb57600080fd5b505afa158015611eff573d6000803e3d6000fd5b505050506040513d6020811015611f1557600080fd5b505190506000611f236138ee565b6001600160a01b031663b410a0346040518163ffffffff1660e01b815260040160206040518083038186803b158015611f5b57600080fd5b505afa158015611f6f573d6000803e3d6000fd5b505050506040513d6020811015611f8557600080fd5b5051905080821015611f9c57600192505050610c18565b60006120306120236018547384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611feb57600080fd5b505af4158015611fff573d6000803e3d6000fd5b505050506040513d602081101561201557600080fd5b50519063ffffffff61348716565b839063ffffffff613a3816565b9050808311156120465760009350505050610c18565b506001949350505050565b6008546000906001600160a01b0383811691161461207157506000610c18565b60005b600a5481101561217c576000600a828154811061208d57fe5b6000918252602080832090910154808352600982526040928390205460085484517f21f8a7210000000000000000000000000000000000000000000000000000000081526004810184905294519295506001600160a01b03918216949116926321f8a72192602480840193829003018186803b15801561210c57600080fd5b505afa158015612120573d6000803e3d6000fd5b505050506040513d602081101561213657600080fd5b50516001600160a01b031614158061216357506000818152600960205260409020546001600160a01b0316155b1561217357600092505050610c18565b50600101612074565b50600192915050565b6002546000906001600160a01b031633148015906121ae57506003546001600160a01b03163314155b80156121c557506004546001600160a01b03163314155b156121dd57600480546001600160a01b031916331790555b6121e5613a62565b60048054604080517f21f4ae570000000000000000000000000000000000000000000000000000000081526001600160a01b038781169482019490945291831660248301525192909116916321f4ae5791604480820192602092909190829003018186803b15801561225657600080fd5b505afa15801561226a573d6000803e3d6000fd5b505050506040513d602081101561228057600080fd5b50516122d3576040805162461bcd60e51b815260206004820152601f60248201527f4e6f7420617070726f76656420746f20636c61696d206f6e20626568616c6600604482015290519081900360640190fd5b610dc882613aa6565b60008060015b6002811015611e85576123086122f78261326b565b60030154839063ffffffff61348716565b91506123276123168261326b565b60040154839063ffffffff61329516565b91506001016122e2565b6001546001600160a01b0316331461237a5760405162461bcd60e51b81526004018080602001828103825260358152602001806146f96035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60006123f7613227565b6001600160a01b031663bdc963d87f73796e74685f65786368616e67655f6665655f72617465000000000000000000846040516020018083815260200182815260200192505050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610be957600080fd5b612490613c24565b6001600160a01b0316336001600160a01b0316146124f5576040805162461bcd60e51b815260206004820152601f60248201527f466565506f6f6c3a204f6e6c792049737375657220417574686f726973656400604482015290519081900360640190fd5b6124fd6132f2565b6001600160a01b03166394e1a448848484612518600061326b565b54604080517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526001600160a01b0390951660048601526024850193909352604484019190915267ffffffffffffffff6801000000000000000090910416606483015251608480830192600092919082900301818387803b1580156125a357600080fd5b505af11580156125b7573d6000803e3d6000fd5b505050506125e78383836125cb600061326b565b5468010000000000000000900467ffffffffffffffff16613c85565b505050565b6000546001600160a01b031681565b6000546001600160a01b031633146126445760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9181900360200190a150565b6000546001600160a01b031633146126e15760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b60065460ff16612738576040805162461bcd60e51b815260206004820152601f60248201527f53656c66204465737472756374206e6f742079657420696e6974696174656400604482015290519081900360640190fd5b426224ea006005540110612793576040805162461bcd60e51b815260206004820152601b60248201527f53656c662064657374727563742064656c6179206e6f74206d65740000000000604482015290519081900360640190fd5b600654604080516101009092046001600160a01b03168252517f8a09e1677ced846cb537dc2b172043bd05a1a81ad7e0033a7ef8ba762df990b7916020908290030190a160065461010090046001600160a01b0316ff5b6003546001600160a01b031681565b6224ea0081565b6128086146bb565b60005b600a5481101561284657600a818154811061282257fe5b906000526020600020015482826018811061283957fe5b602002015260010161280b565b5090565b6000806128556138ee565b6001600160a01b031663b410a0346040518163ffffffff1660e01b815260040160206040518083038186803b15801561288d57600080fd5b505afa1580156128a1573d6000803e3d6000fd5b505050506040513d60208110156128b757600080fd5b5051601854604080517f907af6c0000000000000000000000000000000000000000000000000000000008152905192935061293a9261292d92917384d626b2bb4d0f064067e4bf80fce7055d8f3e7b9163907af6c091600480820192602092909190829003018186803b158015611feb57600080fd5b829063ffffffff613a3816565b91505090565b6002546001600160a01b0316331480159061296657506003546001600160a01b03163314155b801561297d57506004546001600160a01b03163314155b1561299557600480546001600160a01b031916331790555b6000546004546001600160a01b039081169116146129f0576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b6007544210612a305760405162461bcd60e51b815260040180806020018281038252602981526020018061487e6029913960400191505060405180910390fd5b612a386138ee565b6001600160a01b031663cd92eba96040518163ffffffff1660e01b815260040160206040518083038186803b158015612a7057600080fd5b505afa158015612a84573d6000803e3d6000fd5b505050506040513d6020811015612a9a57600080fd5b5051861115612af0576040805162461bcd60e51b815260206004820152601660248201527f43616e6e6f7420696d706f727420626164206461746100000000000000000000604482015290519081900360640190fd5b6040518060e001604052808867ffffffffffffffff1681526020018767ffffffffffffffff1681526020018667ffffffffffffffff16815260200185815260200184815260200183815260200182815250600c612b60600260ff16611bac8c60165461348790919063ffffffff16565b60028110612b6a57fe5b82516005919091029190910180546020840151604085015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff000000000000000019166801000000000000000091851691909102177fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16600160801b9390911692909202919091178155606082015160018201556080820151600282015560a0820151600382015560c0909101516004909101555050505050505050565b6002546001600160a01b03163314801590612c5057506003546001600160a01b03163314155b8015612c6757506004546001600160a01b03163314155b15612c7f57600480546001600160a01b031916331790555b6000546004546001600160a01b03908116911614612cda576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b612ce2613549565b6004546001600160a01b03918216916323b872dd9116612d00613dcc565b846040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015612d6957600080fd5b505af1158015612d7d573d6000803e3d6000fd5b505050506040513d6020811015612d9357600080fd5b50612d9e9050613dcc565b6001600160a01b031663b5ddb9c783836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612dfd57600080fd5b505af1158015612e11573d6000803e3d6000fd5b505050505050565b60065460ff1681565b6002546001600160a01b0316331480612e4557506003546001600160a01b031633145b612e96576040805162461bcd60e51b815260206004820152601760248201527f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000604482015290519081900360640190fd5b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314612f015760405162461bcd60e51b815260040180806020018281038252602f81526020018061480b602f913960400191505060405180910390fd5b426005556006805460ff19166001179055604080516224ea00815290517fcbd94ca75b8dc45c9d80c77e851670e78843c0d75180cb81db3e2158228fa9a69181900360200190a1565b60065461010090046001600160a01b031681565b600a8181548110612f6b57fe5b600091825260209091200154905081565b600281565b6002546000906001600160a01b03163314801590612faa57506003546001600160a01b03163314155b8015612fc157506004546001600160a01b03163314155b15612fd957600480546001600160a01b031916331790555b600454612fee906001600160a01b0316613aa6565b905090565b6201518081565b6004546001600160a01b031681565b60185481565b601881565b73feefeefeefeefeefeefeefeefeefeefeefeefeef81565b6002546001600160a01b031681565b624f1a0081565b67016345785d8a000081565b6000613058613e2d565b6004549091506001600160a01b038083169116148061307f5750336001600160a01b038216145b6130d0576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f742072657761726473417574686f726974790000604482015290519081900360640190fd5b6130ee826130de600061326b565b600301549063ffffffff61348716565b6130f8600061326b565b600301555050565b60025460408051602080820185905282518083039091018152908201918290526001600160a01b039092169163907dff97916001908060216147ea82396021019050604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156131c25781810151838201526020016131aa565b50505050905090810190601f1680156131ef5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b15801561321357600080fd5b505af1158015611429573d6000803e3d6000fd5b6000612fee7f466565506f6f6c457465726e616c53746f7261676500000000000000000000006040518060600160405280602581526020016148f060259139613e6d565b6000600c600260ff1683601654018161328057fe5b066002811061328b57fe5b6005020192915050565b6000828211156132ec576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000612fee7f466565506f6f6c537461746500000000000000000000000000000000000000006040518060400160405280601c81526020017f4d697373696e6720466565506f6f6c5374617465206164647265737300000000815250613e6d565b60008061335e6138ee565b9050600061347d85613471846001600160a01b03166308d95cd5886040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d60208110156133d757600080fd5b5051604080517f08d95cd5000000000000000000000000000000000000000000000000000000008152600481018c905290516001600160a01b038816916308d95cd5916024808301926020929190829003018186803b15801561343957600080fd5b505afa15801561344d573d6000803e3d6000fd5b505050506040513d602081101561346357600080fd5b50519063ffffffff613f1716565b9063ffffffff613f3016565b9695505050505050565b6000828201838110156134e1576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000612fee7f45786368616e67657200000000000000000000000000000000000000000000006040518060400160405280601981526020017f4d697373696e672045786368616e676572206164647265737300000000000000815250613e6d565b6000612fee7f53796e74686574697800000000000000000000000000000000000000000000006040518060400160405280601981526020017f4d697373696e672053796e746865746978206164647265737300000000000000815250613e6d565b60025460408051602081018590528082018490528151808203830181526060909101918290526001600160a01b039092169163907dff97916001908060286148a782396028019050604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b8381101561367257818101518382015260200161365a565b50505050905090810190601f16801561369f5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b158015612dfd57600080fd5b6000826136d257506000610dc8565b828202828482816136df57fe5b04146134e15760405162461bcd60e51b815260040180806020018281038252602181526020018061485d6021913960400191505060405180910390fd5b6000808211613772576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b600082848161377d57fe5b04949350505050565b6000808361379957506000905080613820565b8385156137c45760006137b36001610d0860018a0361326b565b90506137c0818787613353565b9150505b60006137e3826137d38961326b565b600101549063ffffffff613a3816565b90506000613804836137f48a61326b565b600301549063ffffffff613a3816565b905061380f82613f49565b61381882613f49565b945094505050505b935093915050565b6000612fee7f53797374656d53746174757300000000000000000000000000000000000000006040518060400160405280601c81526020017f4d697373696e672053797374656d537461747573206164647265737300000000815250613e6d565b6000816138dd576040805162461bcd60e51b815260206004820152601860248201527f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000604482015290519081900360640190fd5b8183816138e657fe5b069392505050565b6000612fee7f53796e74686574697853746174650000000000000000000000000000000000006040518060400160405280601e81526020017f4d697373696e672053796e746865746978537461746520616464726573730000815250613e6d565b6002546040805160208082018590528251808303820181528284018085527f466565506572696f64436c6f7365642875696e74323536290000000000000000905292519182900360580182207f907dff97000000000000000000000000000000000000000000000000000000008352600160248401819052604484018290526000606485018190526084850181905260a4850181905260c060048601908152865160c487015286516001600160a01b039098169763907dff979796939592938493849392839260e401918a019080838388838110156131c25781810151838201526020016131aa565b6000670de0b6b3a7640000613a53848463ffffffff6136c316565b81613a5a57fe5b049392505050565b6000612fee7f44656c6567617465417070726f76616c7300000000000000000000000000000060405180606001604052806021815260200161475260219139613e6d565b6000613ab0613828565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015613ae857600080fd5b505afa158015613afc573d6000803e3d6000fd5b506000925082915081905080613b1186611e8b565b613b62576040805162461bcd60e51b815260206004820152601f60248201527f432d526174696f2062656c6f772070656e616c7479207468726573686f6c6400604482015290519081900360640190fd5b613b6b86610dce565b909250905081151580613b7e5750600081115b613bb95760405162461bcd60e51b81526004018080602001828103825260408152602001806147aa6040913960400191505060405180910390fd5b613bd786613bc7600161326b565b5467ffffffffffffffff16613f6b565b8115613bf257613be682614023565b9250613bf286846140f7565b8015613c0d57613c01816142dc565b9350613c0d86856143b6565b613c188684866144ad565b50600195945050505050565b6000612fee7f49737375657200000000000000000000000000000000000000000000000000006040518060400160405280601681526020017f4d697373696e6720497373756572206164647265737300000000000000000000815250613e6d565b6002805460408051602081018790528082018690526060808201869052825180830390910181526080909101918290526001600160a01b039092169263907dff979291806037614773823960370190506040518091039020886001600160a01b031660001b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015613d5d578181015183820152602001613d45565b50505050905090810190601f168015613d8a5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b158015613dae57600080fd5b505af1158015613dc2573d6000803e3d6000fd5b5050505050505050565b6000612fee7f526577617264457363726f7700000000000000000000000000000000000000006040518060400160405280601c81526020017f4d697373696e6720526577617264457363726f77206164647265737300000000815250613e6d565b6000612fee7f52657761726473446973747269627574696f6e0000000000000000000000000060405180606001604052806023815260200161483a602391395b6000828152600960205260408120546001600160a01b03168281613f0f5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613ed4578181015183820152602001613ebc565b50505050905090810190601f168015613f015780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b60006134e183836b033b2e3c9fd0803ce80000006145d0565b60006134e183836b033b2e3c9fd0803ce8000000614608565b60006305f5e10082046005600a820610613f6157600a015b600a900492915050565b613f73613227565b6001600160a01b0316633562fd207f6c6173745f6665655f7769746864726177616c000000000000000000000000008460405160200180838152602001826001600160a01b03166001600160a01b031660601b81526014019250505060405160208183030381529060405280519060200120836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b158015612dfd57600080fd5b6000818160015b6002811015613f0f57600061403e8261326b565b6002015490506000614063826140538561326b565b600101549063ffffffff61329516565b905080156140ec57600085821061407a578561407c565b815b905061408e838263ffffffff61348716565b6140978561326b565b600201556140ab868263ffffffff61329516565b95506140bd858263ffffffff61348716565b9450856140d257849650505050505050610c18565b831580156140e05750600086115b156140ea57600095505b505b50506000190161402a565b816001600160a01b03811673feefeefeefeefeefeefeefeefeefeefeefeefeef141561416a576040805162461bcd60e51b815260206004820152601760248201527f4665652061646472657373206e6f7420616c6c6f776564000000000000000000604482015290519081900360640190fd5b6000614174613549565b6001600160a01b03166332608039600b546040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156141b957600080fd5b505afa1580156141cd573d6000803e3d6000fd5b505050506040513d60208110156141e357600080fd5b5051604080517f9dc29fac00000000000000000000000000000000000000000000000000000000815273feefeefeefeefeefeefeefeefeefeefeefeefeef60048201526024810186905290519192506001600160a01b03831691639dc29fac9160448082019260009290919082900301818387803b15801561426457600080fd5b505af1158015614278573d6000803e3d6000fd5b50505050806001600160a01b031663867904b485856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613dae57600080fd5b6000818160015b6002811015613f0f5760006143176142fa8361326b565b600401546143078461326b565b600301549063ffffffff61329516565b905080156143ac57600084821061432e5784614330565b815b905061434f8161433f8561326b565b600401549063ffffffff61348716565b6143588461326b565b6004015561436c858263ffffffff61329516565b945061437e848263ffffffff61348716565b935084614392578395505050505050610c18565b821580156143a05750600085115b156143aa57600094505b505b50600019016142e3565b816001600160a01b03811673feefeefeefeefeefeefeefeefeefeefeefeefeef1415614429576040805162461bcd60e51b815260206004820152601760248201527f4665652061646472657373206e6f7420616c6c6f776564000000000000000000604482015290519081900360640190fd5b614431613dcc565b6001600160a01b031663b5ddb9c784846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561449057600080fd5b505af11580156144a4573d6000803e3d6000fd5b50505050505050565b600254604080516001600160a01b0386811660208301528183018690526060808301869052835180840390910181526080909201928390529092169163907dff979160019080602461472e82396024019050604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b8381101561457f578181015183820152602001614567565b50505050905090810190601f1680156145ac5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b15801561449057600080fd5b6000806145ea846115bb87600a870263ffffffff6136c316565b90506005600a825b06106145fc57600a015b600a9004949350505050565b600080600a830461461f868663ffffffff6136c316565b8161462657fe5b0490506005600a826145f2565b60405180604001604052806002905b61464a6146da565b8152602001906001900390816146425790505090565b6040518060e00160405280600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600081526020016000815260200160008152602001600081525090565b6040518061030001604052806018906020820280388339509192915050565b6040518060400160405280600290602082028038833950919291505056fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e65727368697046656573436c61696d656428616464726573732c75696e743235362c75696e74323536294d697373696e672044656c6567617465417070726f76616c73206164647265737349737375616e636544656274526174696f456e74727928616464726573732c75696e743235362c75696e743235362c75696e74323536294e6f2066656573206f72207265776172647320617661696c61626c6520666f7220706572696f642c206f72206665657320616c726561647920636c61696d6564466565506572696f644475726174696f6e557064617465642875696e74323536294f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e4d697373696e672052657761726473446973747269627574696f6e2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616e206f6e6c7920706572666f726d207468697320616374696f6e20647572696e6720736574757053796e746845786368616e67654665655570646174656428627974657333322c75696e74323536294f6e6c792045786368616e6765722c2053796e74687320417574686f72697365644d697373696e6720466565506f6f6c457465726e616c53746f726167652061646472657373a265627a7a72315820df3d94c204228d52bdeab83f2e8f4a1142a185790336acf62f2437c0d7be5c7264736f6c63430005100032

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

000000000000000000000000b440dd674e1243644791a4adfe3a2abb0a92d309000000000000000000000000de910777c787903f78c89e7a0bf7f4c435cbb1fe000000000000000000000000fbb6526ed92da8915d4843a86166020d0b7baad0

-----Decoded View---------------
Arg [0] : _proxy (address): 0xb440DD674e1243644791a4AdfE3A2AbB0A92d309
Arg [1] : _owner (address): 0xDe910777C787903F78C89e7a0bf7F4C435cBB1Fe
Arg [2] : _resolver (address): 0xFbB6526ed92DA8915d4843a86166020d0B7bAAd0

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000b440dd674e1243644791a4adfe3a2abb0a92d309
Arg [1] : 000000000000000000000000de910777c787903f78c89e7a0bf7f4c435cbb1fe
Arg [2] : 000000000000000000000000fbb6526ed92da8915d4843a86166020d0b7baad0


Libraries Used


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

Synthetix: Fee Pool contract has migrated to 0x6AAeBDfbf23134eF8d81deB2E253f32394B2857B.

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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.