Contract 0x923F8f53c9BD1f0C84745394E47ea31c5949eF96

Contract Overview

Balance:
0 Ether
Txn Hash
Method
Block
From
To
Value
0xb58027a3f3f5c11953998cacbd103f431bd9814c02f2f0a37ec501f6eaba4559Add Synths315768192022-05-13 5:43:2052 days 17 hrs ago0x73570075092502472e4b61a7058df1a4a1db12f2 IN  0x923f8f53c9bd1f0c84745394e47ea31c5949ef960 Ether0.00088471 1
0xbef526829498453b8f7d998c367669804097da232f33020e4001c884614c53110x60806040315767812022-05-13 5:40:2452 days 18 hrs ago0x73570075092502472e4b61a7058df1a4a1db12f2 IN  Create: Issuer0 Ether0.00517097 1
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x54a67c86994790dabde8d294e5c052863ffe5cd10 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xf7440b98b0dc9b54bfae68288a11c48dabfe7d070 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x9a6e96a0d9cdd4213bad9101ab7c4d7bd1ea52260 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x0f46148d93b52e2b503fe84897609913cba42b7a0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x2c3d51c7b454cb045c8cec92d2f9e717c75191060 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x0f46148d93b52e2b503fe84897609913cba42b7a0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x9c333f576bbab9ac0f2585aaaa7a094ef72f56960 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xb1751e5ede811288ce2fc4c65aaca17a955366be0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x2c3d51c7b454cb045c8cec92d2f9e717c75191060 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xb1751e5ede811288ce2fc4c65aaca17a955366be0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x9c333f576bbab9ac0f2585aaaa7a094ef72f56960 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x64ac15ab583fffa6a7401b83e3aa5cf4ad1aa92a0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x548c18a49a66ad1238e17824c18b0b9be35fb6040 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xd802079cbdd5e99c2e301079bc643b99b2cd05c90 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x412c870daab642aa87715e2ea860d20e48e732670 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x2c3d51c7b454cb045c8cec92d2f9e717c75191060 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x412c870daab642aa87715e2ea860d20e48e732670 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xb1751e5ede811288ce2fc4c65aaca17a955366be0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xb1751e5ede811288ce2fc4c65aaca17a955366be0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x2c3d51c7b454cb045c8cec92d2f9e717c75191060 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x5cf1651f6d2071dd8e3e18c7462f47d578b497770 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0x0f46148d93b52e2b503fe84897609913cba42b7a0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xb9713d033df6190d941f169cdedc1c69b5314e720 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xb1751e5ede811288ce2fc4c65aaca17a955366be0 Ether
0xe5fc79e11f27bf50a5d20ea3d92063f95053dd3db36871851439a83c6dceec10320736622022-06-08 16:53:4826 days 6 hrs ago 0x923f8f53c9bd1f0c84745394e47ea31c5949ef96 0xb1751e5ede811288ce2fc4c65aaca17a955366be0 Ether
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Issuer

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-05-13
*/

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

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



pragma solidity ^0.5.16;

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

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

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

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

    modifier onlyOwner {
        _onlyOwner();
        _;
    }

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

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


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

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

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


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

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

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

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

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

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


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

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

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

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

    function availableSynthCount() external view returns (uint);

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

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

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

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

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

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

    function issuanceRatio() external view returns (uint);

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

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

    function minimumStakeTime() external view returns (uint);

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

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

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

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

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

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

    // 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 burnForRedemption(
        address deprecatedSynthProxy,
        address account,
        uint balance
    ) external;

    function setCurrentPeriodId(uint128 periodId) external;

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

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

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


// Inheritance


// Internal references


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

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

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

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

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

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

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

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

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

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

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

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

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

    event AddressImported(bytes32 name, address destination);
}


// Internal references


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

    mapping(bytes32 => address) private addressCache;

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

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

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

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

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

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

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

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

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

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

        return true;
    }

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

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

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

    event CacheUpdated(bytes32 name, address destination);
}


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

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

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

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

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

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

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

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

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

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

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

    function deleteIntValue(bytes32 contractName, bytes32 record) external;

    function deleteAddressValue(bytes32 contractName, bytes32 record) external;

    function deleteBoolValue(bytes32 contractName, bytes32 record) external;

    function deleteBytes32Value(bytes32 contractName, bytes32 record) external;

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

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

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

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

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

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

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

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

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

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


// Internal references


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

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

    bytes32 internal constant CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


// SPDX-License-Identifier: MIT


/**
 * @dev Wrappers over Solidity's uintXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}


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

        return c;
    }

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

        return c;
    }

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

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

        return c;
    }

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

        return c;
    }

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


// Libraries


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

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

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

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

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

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

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

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

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

        return quotientTimesTen / 10;
    }

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

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

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

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

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

        return resultTimesTen / 10;
    }

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

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

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

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

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

        return quotientTimesTen / 10;
    }

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

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

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


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

    function rate() external view returns (uint);

    function readyToSettle() external view returns (bool);

    function secsLeftInWaitingPeriod() external view returns (uint);

    function settled() external view returns (bool);

    function synth() external view returns (ISynth);

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


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

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

    function availableSynthCount() external view returns (uint);

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

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

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

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

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

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

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

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

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

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

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

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

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

    function burnSynthsOnBehalf(address burnForAddress, uint amount) external;

    function burnSynthsToTarget() external;

    function burnSynthsToTargetOnBehalf(address burnForAddress) external;

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

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

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

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

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

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

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

    function issueMaxSynths() external;

    function issueMaxSynthsOnBehalf(address issueForAddress) external;

    function issueSynths(uint amount) external;

    function issueSynthsOnBehalf(address issueForAddress, uint amount) external;

    function mint() external returns (bool);

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

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

    function liquidateSelf() external returns (bool);

    // Restricted Functions

    function mintSecondary(address account, uint amount) external;

    function mintSecondaryRewards(uint amount) external;

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


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

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

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

    function feePeriodDuration() external view returns (uint);

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

    function targetThreshold() external view returns (uint);

    function totalFeesAvailable() external view returns (uint);

    function totalRewardsAvailable() external view returns (uint);

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

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

    function closeCurrentFeePeriod() external;

    function closeSecondary(uint snxBackedDebt, uint debtShareSupply) external;

    function recordFeePaid(uint sUSDAmount) external;

    function setRewardsToDistribute(uint amount) external;
}


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

    function currentPeriodId() external view returns (uint128);

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

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

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

    function totalSupply() external view returns (uint);

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

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

    // Mutative functions

    function takeSnapshot(uint128 id) external;

    function mintShare(address account, uint256 amount) external;

    function burnShare(address account, uint256 amount) external;

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

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

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

    function addAuthorizedBroker(address target) external;

    function removeAuthorizedBroker(address target) external;

    function addAuthorizedToSnapshot(address target) external;

    function removeAuthorizedToSnapshot(address target) external;
}


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

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

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

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

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

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

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

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

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

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

    function priceDeviationThresholdFactor() external view returns (uint);

    function waitingPeriodSecs() external view returns (uint);

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

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

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

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

    function suspendSynthWithInvalidRate(bytes32 currencyKey) external;
}


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

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

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

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

    // Mutative
    function approveAllDelegatePowers(address delegate) external;

    function removeAllDelegatePowers(address delegate) external;

    function approveBurnOnBehalf(address delegate) external;

    function removeBurnOnBehalf(address delegate) external;

    function approveIssueOnBehalf(address delegate) external;

    function removeIssueOnBehalf(address delegate) external;

    function approveClaimOnBehalf(address delegate) external;

    function removeClaimOnBehalf(address delegate) external;

    function approveExchangeOnBehalf(address delegate) external;

    function removeExchangeOnBehalf(address delegate) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/iexchangerates
interface IExchangeRates {
    // Structs
    struct RateAndUpdatedTime {
        uint216 rate;
        uint40 time;
    }

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

    function aggregatorWarningFlags() external view returns (address);

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

    function anyRateIsInvalidAtRound(bytes32[] calldata currencyKeys, uint[] calldata roundIds) external view returns (bool);

    function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory);

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

    function effectiveValueAndRates(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey
    )
        external
        view
        returns (
            uint value,
            uint sourceRate,
            uint destinationRate
        );

    function effectiveValueAndRatesAtRound(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        uint roundIdForSrc,
        uint roundIdForDest
    )
        external
        view
        returns (
            uint value,
            uint sourceRate,
            uint destinationRate
        );

    function effectiveAtomicValueAndRates(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey
    )
        external
        view
        returns (
            uint value,
            uint systemValue,
            uint systemSourceRate,
            uint systemDestinationRate
        );

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

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

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

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

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

    function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid);

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

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

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

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

    function rateStalePeriod() external view returns (uint);

    function ratesAndUpdatedTimeForCurrencyLastNRounds(
        bytes32 currencyKey,
        uint numRounds,
        uint roundId
    ) external view returns (uint[] memory rates, uint[] memory times);

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

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

    function synthTooVolatileForAtomicExchange(bytes32 currencyKey) external view returns (bool);
}


// https://docs.synthetix.io/contracts/source/interfaces/ihasbalance
interface IHasBalance {
    // Views
    function balanceOf(address account) external view returns (uint);
}


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

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

    function decimals() external view returns (uint8);

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

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

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

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

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

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

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

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


interface ILiquidator {
    // Views
    function issuanceRatio() external view returns (uint);

    function liquidationDelay() external view returns (uint);

    function liquidationRatio() external view returns (uint);

    function liquidationEscrowDuration() external view returns (uint);

    function liquidationPenalty() external view returns (uint);

    function selfLiquidationPenalty() external view returns (uint);

    function liquidateReward() external view returns (uint);

    function flagReward() external view returns (uint);

    function liquidationCollateralRatio() external view returns (uint);

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

    function getLiquidationCallerForAccount(address account) external view returns (address);

    function isLiquidationOpen(address account, bool isSelfLiquidation) external view returns (bool);

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

    function calculateAmountToFixCollateral(
        uint debtBalance,
        uint collateral,
        uint penalty
    ) external view returns (uint);

    // Mutative Functions
    function flagAccountForLiquidation(address account) external;

    // Restricted: used internally to Synthetix contracts
    function removeAccountInLiquidation(address account) external;

    function checkAndRemoveAccountInLiquidation(address account) external;
}


interface ILiquidatorRewards {
    // Views

    function earned(address account) external view returns (uint256);

    // Mutative

    function getReward(address account) external;

    function notifyRewardAmount(uint256 reward) external;

    function updateEntry(address account) external;
}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function removeCollaterals(address[] calldata collaterals) external;

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

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

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

    function removeShortableSynths(bytes32[] calldata synths) external;

    // State mutative

    function incrementLongs(bytes32 synth, uint amount) external;

    function decrementLongs(bytes32 synth, uint amount) external;

    function incrementShorts(bytes32 synth, uint amount) external;

    function decrementShorts(bytes32 synth, uint amount) external;

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

    function updateBorrowRatesCollateral(uint rate) external;

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


pragma experimental ABIEncoderV2;

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

interface IRewardEscrowV2 {
    // 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);

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

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

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

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

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

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

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

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

    function migrateVestingSchedule(address _addressToMigrate) external;

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

    // Account Merging
    function startMergingWindow() external;

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

    function nominateAccountToMerge(address account) external;

    function accountMergingIsOpen() external view returns (bool);

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

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


interface ISynthRedeemer {
    // Rate of redemption - 0 for none
    function redemptions(address synthProxy) external view returns (uint redeemRate);

    // sUSD balance of deprecated token holder
    function balanceOf(IERC20 synthProxy, address account) external view returns (uint balanceOfInsUSD);

    // Full sUSD supply of token
    function totalSupply(IERC20 synthProxy) external view returns (uint totalSupplyInsUSD);

    function redeem(IERC20 synthProxy) external;

    function redeemAll(IERC20[] calldata synthProxies) external;

    function redeemPartial(IERC20 synthProxy, uint amountOfSynth) external;

    // Restricted to Issuer
    function deprecate(IERC20 synthProxy, uint rateToRedeem) external;
}


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

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

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

    function requireSystemActive() external view;

    function systemSuspended() external view returns (bool);

    function requireIssuanceActive() external view;

    function requireExchangeActive() external view;

    function requireFuturesActive() external view;

    function requireFuturesMarketActive(bytes32 marketKey) external view;

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

    function requireSynthActive(bytes32 currencyKey) external view;

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

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

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

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

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

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

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

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

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

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

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

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

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

    function suspendSynth(bytes32 currencyKey, uint256 reason) external;

    function suspendFuturesMarket(bytes32 marketKey, uint256 reason) external;

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


// Inheritance


// Internal references


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

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

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

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

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

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

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

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

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

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

    event TargetUpdated(Proxyable newTarget);
}


// Inheritance


// Internal references


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

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

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

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

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

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

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

    modifier onlyProxy {
        _onlyProxy();
        _;
    }

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

    modifier optionalProxy {
        _optionalProxy();
        _;
    }

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

    modifier optionalProxy_onlyOwner {
        _optionalProxy_onlyOwner();
        _;
    }

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

    event ProxyUpdated(address proxyAddress);
}


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

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


interface AggregatorV3Interface {

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

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

}


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

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

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

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

}


// Inheritance


// Libraries


// Internal references


interface IProxy {
    function target() external view returns (address);
}

interface IIssuerInternalDebtCache {
    function updateCachedSynthDebtWithRate(bytes32 currencyKey, uint currencyRate) external;

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

    function updateDebtCacheValidity(bool currentlyInvalid) external;

    function totalNonSnxBackedDebt() external view returns (uint excludedDebt, bool isInvalid);

    function cacheInfo()
        external
        view
        returns (
            uint cachedDebt,
            uint timestamp,
            bool isInvalid,
            bool isStale
        );

    function updateCachedsUSDDebt(int amount) external;
}

// https://docs.synthetix.io/contracts/source/contracts/issuer
contract Issuer is Owned, MixinSystemSettings, IIssuer {
    using SafeMath for uint;
    using SafeDecimalMath for uint;

    bytes32 public constant CONTRACT_NAME = "Issuer";

    // SIP-165: Circuit breaker for Debt Synthesis
    uint public constant CIRCUIT_BREAKER_SUSPENSION_REASON = 165;

    // Available Synths which can be used with the system
    ISynth[] public availableSynths;
    mapping(bytes32 => ISynth) public synths;
    mapping(address => bytes32) public synthsByAddress;

    uint public lastDebtRatio;

    /* ========== ENCODED NAMES ========== */

    bytes32 internal constant sUSD = "sUSD";
    bytes32 internal constant sETH = "sETH";
    bytes32 internal constant SNX = "SNX";

    // Flexible storage names

    bytes32 internal constant LAST_ISSUE_EVENT = "lastIssueEvent";

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

    bytes32 private constant CONTRACT_SYNTHETIX = "Synthetix";
    bytes32 private constant CONTRACT_EXCHANGER = "Exchanger";
    bytes32 private constant CONTRACT_EXRATES = "ExchangeRates";
    bytes32 private constant CONTRACT_SYNTHETIXDEBTSHARE = "SynthetixDebtShare";
    bytes32 private constant CONTRACT_FEEPOOL = "FeePool";
    bytes32 private constant CONTRACT_DELEGATEAPPROVALS = "DelegateApprovals";
    bytes32 private constant CONTRACT_REWARDESCROW_V2 = "RewardEscrowV2";
    bytes32 private constant CONTRACT_SYNTHETIXESCROW = "SynthetixEscrow";
    bytes32 private constant CONTRACT_LIQUIDATOR = "Liquidator";
    bytes32 private constant CONTRACT_LIQUIDATOR_REWARDS = "LiquidatorRewards";
    bytes32 private constant CONTRACT_DEBTCACHE = "DebtCache";
    bytes32 private constant CONTRACT_SYNTHREDEEMER = "SynthRedeemer";
    bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus";
    bytes32 private constant CONTRACT_SYNTHETIXBRIDGETOOPTIMISM = "SynthetixBridgeToOptimism";
    bytes32 private constant CONTRACT_SYNTHETIXBRIDGETOBASE = "SynthetixBridgeToBase";

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

    constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) {}

    /* ========== VIEWS ========== */
    function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
        bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired();
        bytes32[] memory newAddresses = new bytes32[](15);
        newAddresses[0] = CONTRACT_SYNTHETIX;
        newAddresses[1] = CONTRACT_EXCHANGER;
        newAddresses[2] = CONTRACT_EXRATES;
        newAddresses[3] = CONTRACT_SYNTHETIXDEBTSHARE;
        newAddresses[4] = CONTRACT_FEEPOOL;
        newAddresses[5] = CONTRACT_DELEGATEAPPROVALS;
        newAddresses[6] = CONTRACT_REWARDESCROW_V2;
        newAddresses[7] = CONTRACT_SYNTHETIXESCROW;
        newAddresses[8] = CONTRACT_LIQUIDATOR;
        newAddresses[9] = CONTRACT_LIQUIDATOR_REWARDS;
        newAddresses[10] = CONTRACT_DEBTCACHE;
        newAddresses[11] = CONTRACT_SYNTHREDEEMER;
        newAddresses[12] = CONTRACT_SYSTEMSTATUS;
        newAddresses[13] = CONTRACT_EXT_AGGREGATOR_ISSUED_SYNTHS;
        newAddresses[14] = CONTRACT_EXT_AGGREGATOR_DEBT_RATIO;
        return combineArrays(existingAddresses, newAddresses);
    }

    function synthetix() internal view returns (ISynthetix) {
        return ISynthetix(requireAndGetAddress(CONTRACT_SYNTHETIX));
    }

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

    function exchangeRates() internal view returns (IExchangeRates) {
        return IExchangeRates(requireAndGetAddress(CONTRACT_EXRATES));
    }

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

    function feePool() internal view returns (IFeePool) {
        return IFeePool(requireAndGetAddress(CONTRACT_FEEPOOL));
    }

    function liquidator() internal view returns (ILiquidator) {
        return ILiquidator(requireAndGetAddress(CONTRACT_LIQUIDATOR));
    }

    function liquidatorRewards() internal view returns (ILiquidatorRewards) {
        return ILiquidatorRewards(requireAndGetAddress(CONTRACT_LIQUIDATOR_REWARDS));
    }

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

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

    function synthetixEscrow() internal view returns (IHasBalance) {
        return IHasBalance(requireAndGetAddress(CONTRACT_SYNTHETIXESCROW));
    }

    function debtCache() internal view returns (IIssuerInternalDebtCache) {
        return IIssuerInternalDebtCache(requireAndGetAddress(CONTRACT_DEBTCACHE));
    }

    function synthRedeemer() internal view returns (ISynthRedeemer) {
        return ISynthRedeemer(requireAndGetAddress(CONTRACT_SYNTHREDEEMER));
    }

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

    function allNetworksDebtInfo()
        public
        view
        returns (
            uint256 debt,
            uint256 sharesSupply,
            bool isStale
        )
    {
        (, int256 rawIssuedSynths, , uint issuedSynthsUpdatedAt, ) =
            AggregatorV2V3Interface(requireAndGetAddress(CONTRACT_EXT_AGGREGATOR_ISSUED_SYNTHS)).latestRoundData();

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

        debt = uint(rawIssuedSynths);
        sharesSupply = rawRatio == 0 ? 0 : debt.divideDecimalRoundPrecise(uint(rawRatio));
        isStale =
            block.timestamp - getRateStalePeriod() > issuedSynthsUpdatedAt ||
            block.timestamp - getRateStalePeriod() > ratioUpdatedAt;
    }

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

    function _sharesForDebt(uint debtAmount) internal view returns (uint) {
        (, int256 rawRatio, , , ) =
            AggregatorV2V3Interface(requireAndGetAddress(CONTRACT_EXT_AGGREGATOR_DEBT_RATIO)).latestRoundData();

        return rawRatio == 0 ? 0 : debtAmount.divideDecimalRoundPrecise(uint(rawRatio));
    }

    function _debtForShares(uint sharesAmount) internal view returns (uint) {
        (, int256 rawRatio, , , ) =
            AggregatorV2V3Interface(requireAndGetAddress(CONTRACT_EXT_AGGREGATOR_DEBT_RATIO)).latestRoundData();

        return sharesAmount.multiplyDecimalRoundPrecise(uint(rawRatio));
    }

    function _availableCurrencyKeysWithOptionalSNX(bool withSNX) internal view returns (bytes32[] memory) {
        bytes32[] memory currencyKeys = new bytes32[](availableSynths.length + (withSNX ? 1 : 0));

        for (uint i = 0; i < availableSynths.length; i++) {
            currencyKeys[i] = synthsByAddress[address(availableSynths[i])];
        }

        if (withSNX) {
            currencyKeys[availableSynths.length] = SNX;
        }

        return currencyKeys;
    }

    // Returns the total value of the debt pool in currency specified by `currencyKey`.
    // To return only the SNX-backed debt, set `excludeCollateral` to true.
    function _totalIssuedSynths(bytes32 currencyKey, bool excludeCollateral)
        internal
        view
        returns (uint totalIssued, bool anyRateIsInvalid)
    {
        (uint debt, , bool cacheIsInvalid, bool cacheIsStale) = debtCache().cacheInfo();
        anyRateIsInvalid = cacheIsInvalid || cacheIsStale;

        IExchangeRates exRates = exchangeRates();

        // Add total issued synths from non snx collateral back into the total if not excluded
        if (!excludeCollateral) {
            (uint nonSnxDebt, bool invalid) = debtCache().totalNonSnxBackedDebt();
            debt = debt.add(nonSnxDebt);
            anyRateIsInvalid = anyRateIsInvalid || invalid;
        }

        if (currencyKey == sUSD) {
            return (debt, anyRateIsInvalid);
        }

        (uint currencyRate, bool currencyRateInvalid) = exRates.rateAndInvalid(currencyKey);
        return (debt.divideDecimalRound(currencyRate), anyRateIsInvalid || currencyRateInvalid);
    }

    function _debtBalanceOfAndTotalDebt(uint debtShareBalance, bytes32 currencyKey)
        internal
        view
        returns (
            uint debtBalance,
            uint totalSystemValue,
            bool anyRateIsInvalid
        )
    {
        // What's the total value of the system excluding ETH backed synths in their requested currency?
        (uint snxBackedAmount, , bool debtInfoStale) = allNetworksDebtInfo();

        if (debtShareBalance == 0) {
            return (0, snxBackedAmount, debtInfoStale);
        }

        // existing functionality requires for us to convert into the exchange rate specified by `currencyKey`
        (uint currencyRate, bool currencyRateInvalid) = exchangeRates().rateAndInvalid(currencyKey);

        debtBalance = _debtForShares(debtShareBalance).divideDecimalRound(currencyRate);
        totalSystemValue = snxBackedAmount;

        anyRateIsInvalid = currencyRateInvalid || debtInfoStale;
    }

    function _canBurnSynths(address account) internal view returns (bool) {
        return now >= _lastIssueEvent(account).add(getMinimumStakeTime());
    }

    function _lastIssueEvent(address account) internal view returns (uint) {
        //  Get the timestamp of the last issue this account made
        return flexibleStorage().getUIntValue(CONTRACT_NAME, keccak256(abi.encodePacked(LAST_ISSUE_EVENT, account)));
    }

    function _remainingIssuableSynths(address _issuer)
        internal
        view
        returns (
            uint maxIssuable,
            uint alreadyIssued,
            uint totalSystemDebt,
            bool anyRateIsInvalid
        )
    {
        (alreadyIssued, totalSystemDebt, anyRateIsInvalid) = _debtBalanceOfAndTotalDebt(
            synthetixDebtShare().balanceOf(_issuer),
            sUSD
        );
        (uint issuable, bool isInvalid) = _maxIssuableSynths(_issuer);
        maxIssuable = issuable;
        anyRateIsInvalid = anyRateIsInvalid || isInvalid;

        if (alreadyIssued >= maxIssuable) {
            maxIssuable = 0;
        } else {
            maxIssuable = maxIssuable.sub(alreadyIssued);
        }
    }

    function _snxToUSD(uint amount, uint snxRate) internal pure returns (uint) {
        return amount.multiplyDecimalRound(snxRate);
    }

    function _usdToSnx(uint amount, uint snxRate) internal pure returns (uint) {
        return amount.divideDecimalRound(snxRate);
    }

    function _maxIssuableSynths(address _issuer) internal view returns (uint, bool) {
        // What is the value of their SNX balance in sUSD
        (uint snxRate, bool isInvalid) = exchangeRates().rateAndInvalid(SNX);
        uint destinationValue = _snxToUSD(_collateral(_issuer), snxRate);

        // They're allowed to issue up to issuanceRatio of that value
        return (destinationValue.multiplyDecimal(getIssuanceRatio()), isInvalid);
    }

    function _collateralisationRatio(address _issuer) internal view returns (uint, bool) {
        uint totalOwnedSynthetix = _collateral(_issuer);

        (uint debtBalance, , bool anyRateIsInvalid) =
            _debtBalanceOfAndTotalDebt(synthetixDebtShare().balanceOf(_issuer), SNX);

        // it's more gas intensive to put this check here if they have 0 SNX, but it complies with the interface
        if (totalOwnedSynthetix == 0) return (0, anyRateIsInvalid);

        return (debtBalance.divideDecimalRound(totalOwnedSynthetix), anyRateIsInvalid);
    }

    function _collateral(address account) internal view returns (uint) {
        uint balance = IERC20(address(synthetix())).balanceOf(account);

        if (address(synthetixEscrow()) != address(0)) {
            balance = balance.add(synthetixEscrow().balanceOf(account));
        }

        if (address(rewardEscrowV2()) != address(0)) {
            balance = balance.add(rewardEscrowV2().balanceOf(account));
        }

        if (address(liquidatorRewards()) != address(0)) {
            balance = balance.add(liquidatorRewards().earned(account));
        }

        return balance;
    }

    function minimumStakeTime() external view returns (uint) {
        return getMinimumStakeTime();
    }

    function canBurnSynths(address account) external view returns (bool) {
        return _canBurnSynths(account);
    }

    function availableCurrencyKeys() external view returns (bytes32[] memory) {
        return _availableCurrencyKeysWithOptionalSNX(false);
    }

    function availableSynthCount() external view returns (uint) {
        return availableSynths.length;
    }

    function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid) {
        (, anyRateInvalid) = exchangeRates().ratesAndInvalidForCurrencies(_availableCurrencyKeysWithOptionalSNX(true));
    }

    function totalIssuedSynths(bytes32 currencyKey, bool excludeOtherCollateral) external view returns (uint totalIssued) {
        (totalIssued, ) = _totalIssuedSynths(currencyKey, excludeOtherCollateral);
    }

    function lastIssueEvent(address account) external view returns (uint) {
        return _lastIssueEvent(account);
    }

    function collateralisationRatio(address _issuer) external view returns (uint cratio) {
        (cratio, ) = _collateralisationRatio(_issuer);
    }

    function collateralisationRatioAndAnyRatesInvalid(address _issuer)
        external
        view
        returns (uint cratio, bool anyRateIsInvalid)
    {
        return _collateralisationRatio(_issuer);
    }

    function collateral(address account) external view returns (uint) {
        return _collateral(account);
    }

    function debtBalanceOf(address _issuer, bytes32 currencyKey) external view returns (uint debtBalance) {
        ISynthetixDebtShare sds = synthetixDebtShare();

        // What was their initial debt ownership?
        uint debtShareBalance = sds.balanceOf(_issuer);

        // If it's zero, they haven't issued, and they have no debt.
        if (debtShareBalance == 0) return 0;

        (debtBalance, , ) = _debtBalanceOfAndTotalDebt(debtShareBalance, currencyKey);
    }

    function remainingIssuableSynths(address _issuer)
        external
        view
        returns (
            uint maxIssuable,
            uint alreadyIssued,
            uint totalSystemDebt
        )
    {
        (maxIssuable, alreadyIssued, totalSystemDebt, ) = _remainingIssuableSynths(_issuer);
    }

    function maxIssuableSynths(address _issuer) external view returns (uint) {
        (uint maxIssuable, ) = _maxIssuableSynths(_issuer);
        return maxIssuable;
    }

    function transferableSynthetixAndAnyRateIsInvalid(address account, uint balance)
        external
        view
        returns (uint transferable, bool anyRateIsInvalid)
    {
        // How many SNX do they have, excluding escrow?
        // Note: We're excluding escrow here because we're interested in their transferable amount
        // and escrowed SNX are not transferable.

        // How many of those will be locked by the amount they've issued?
        // Assuming issuance ratio is 20%, then issuing 20 SNX of value would require
        // 100 SNX to be locked in their wallet to maintain their collateralisation ratio
        // The locked synthetix value can exceed their balance.
        uint debtBalance;
        (debtBalance, , anyRateIsInvalid) = _debtBalanceOfAndTotalDebt(synthetixDebtShare().balanceOf(account), SNX);
        uint lockedSynthetixValue = debtBalance.divideDecimalRound(getIssuanceRatio());

        // If we exceed the balance, no SNX are transferable, otherwise the difference is.
        if (lockedSynthetixValue >= balance) {
            transferable = 0;
        } else {
            transferable = balance.sub(lockedSynthetixValue);
        }
    }

    function getSynths(bytes32[] calldata currencyKeys) external view returns (ISynth[] memory) {
        uint numKeys = currencyKeys.length;
        ISynth[] memory addresses = new ISynth[](numKeys);

        for (uint i = 0; i < numKeys; i++) {
            addresses[i] = synths[currencyKeys[i]];
        }

        return addresses;
    }

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

    function _addSynth(ISynth synth) internal {
        bytes32 currencyKey = synth.currencyKey();
        require(synths[currencyKey] == ISynth(0), "Synth exists");
        require(synthsByAddress[address(synth)] == bytes32(0), "Synth address already exists");

        availableSynths.push(synth);
        synths[currencyKey] = synth;
        synthsByAddress[address(synth)] = currencyKey;

        emit SynthAdded(currencyKey, address(synth));
    }

    function addSynth(ISynth synth) external onlyOwner {
        _addSynth(synth);
        // Invalidate the cache to force a snapshot to be recomputed. If a synth were to be added
        // back to the system and it still somehow had cached debt, this would force the value to be
        // updated.
        debtCache().updateDebtCacheValidity(true);
    }

    function addSynths(ISynth[] calldata synthsToAdd) external onlyOwner {
        uint numSynths = synthsToAdd.length;
        for (uint i = 0; i < numSynths; i++) {
            _addSynth(synthsToAdd[i]);
        }

        // Invalidate the cache to force a snapshot to be recomputed.
        debtCache().updateDebtCacheValidity(true);
    }

    function _removeSynth(bytes32 currencyKey) internal {
        address synthToRemove = address(synths[currencyKey]);
        require(synthToRemove != address(0), "Synth does not exist");
        require(currencyKey != sUSD, "Cannot remove synth");

        uint synthSupply = IERC20(synthToRemove).totalSupply();

        if (synthSupply > 0) {
            (uint amountOfsUSD, uint rateToRedeem, ) =
                exchangeRates().effectiveValueAndRates(currencyKey, synthSupply, "sUSD");
            require(rateToRedeem > 0, "Cannot remove synth to redeem without rate");
            ISynthRedeemer _synthRedeemer = synthRedeemer();
            synths[sUSD].issue(address(_synthRedeemer), amountOfsUSD);
            // ensure the debt cache is aware of the new sUSD issued
            debtCache().updateCachedsUSDDebt(SafeCast.toInt256(amountOfsUSD));
            _synthRedeemer.deprecate(IERC20(address(Proxyable(address(synthToRemove)).proxy())), rateToRedeem);
        }

        // Remove the synth from the availableSynths array.
        for (uint i = 0; i < availableSynths.length; i++) {
            if (address(availableSynths[i]) == synthToRemove) {
                delete availableSynths[i];

                // Copy the last synth into the place of the one we just deleted
                // If there's only one synth, this is synths[0] = synths[0].
                // If we're deleting the last one, it's also a NOOP in the same way.
                availableSynths[i] = availableSynths[availableSynths.length - 1];

                // Decrease the size of the array by one.
                availableSynths.length--;

                break;
            }
        }

        // And remove it from the synths mapping
        delete synthsByAddress[synthToRemove];
        delete synths[currencyKey];

        emit SynthRemoved(currencyKey, synthToRemove);
    }

    function removeSynth(bytes32 currencyKey) external onlyOwner {
        // Remove its contribution from the debt pool snapshot, and
        // invalidate the cache to force a new snapshot.
        IIssuerInternalDebtCache cache = debtCache();
        cache.updateCachedSynthDebtWithRate(currencyKey, 0);
        cache.updateDebtCacheValidity(true);

        _removeSynth(currencyKey);
    }

    function removeSynths(bytes32[] calldata currencyKeys) external onlyOwner {
        uint numKeys = currencyKeys.length;

        // Remove their contributions from the debt pool snapshot, and
        // invalidate the cache to force a new snapshot.
        IIssuerInternalDebtCache cache = debtCache();
        uint[] memory zeroRates = new uint[](numKeys);
        cache.updateCachedSynthDebtsWithRates(currencyKeys, zeroRates);
        cache.updateDebtCacheValidity(true);

        for (uint i = 0; i < numKeys; i++) {
            _removeSynth(currencyKeys[i]);
        }
    }

    function issueSynthsWithoutDebt(
        bytes32 currencyKey,
        address to,
        uint amount
    ) external onlyTrustedMinters returns (bool rateInvalid) {
        require(address(synths[currencyKey]) != address(0), "Issuer: synth doesn't exist");
        require(amount > 0, "Issuer: cannot issue 0 synths");

        // record issue timestamp
        _setLastIssueEvent(to);

        // Create their synths
        synths[currencyKey].issue(to, amount);

        // Account for the issued debt in the cache
        (uint rate, bool rateInvalid) = exchangeRates().rateAndInvalid(currencyKey);
        debtCache().updateCachedsUSDDebt(SafeCast.toInt256(amount.multiplyDecimal(rate)));

        // returned so that the caller can decide what to do if the rate is invalid
        return rateInvalid;
    }

    function burnSynthsWithoutDebt(
        bytes32 currencyKey,
        address from,
        uint amount
    ) external onlyTrustedMinters returns (bool rateInvalid) {
        require(address(synths[currencyKey]) != address(0), "Issuer: synth doesn't exist");
        require(amount > 0, "Issuer: cannot issue 0 synths");

        exchanger().settle(from, currencyKey);

        // Burn some synths
        synths[currencyKey].burn(from, amount);

        // Account for the burnt debt in the cache. If rate is invalid, the user won't be able to exchange
        (uint rate, bool rateInvalid) = exchangeRates().rateAndInvalid(currencyKey);
        debtCache().updateCachedsUSDDebt(-SafeCast.toInt256(amount.multiplyDecimal(rate)));

        // returned so that the caller can decide what to do if the rate is invalid
        return rateInvalid;
    }

    function issueSynths(address from, uint amount) external onlySynthetix {
        require(amount > 0, "Issuer: cannot issue 0 synths");

        _issueSynths(from, amount, false);
    }

    function issueMaxSynths(address from) external onlySynthetix {
        _issueSynths(from, 0, true);
    }

    function issueSynthsOnBehalf(
        address issueForAddress,
        address from,
        uint amount
    ) external onlySynthetix {
        _requireCanIssueOnBehalf(issueForAddress, from);
        _issueSynths(issueForAddress, amount, false);
    }

    function issueMaxSynthsOnBehalf(address issueForAddress, address from) external onlySynthetix {
        _requireCanIssueOnBehalf(issueForAddress, from);
        _issueSynths(issueForAddress, 0, true);
    }

    function burnSynths(address from, uint amount) external onlySynthetix {
        _voluntaryBurnSynths(from, amount, false);
    }

    function burnSynthsOnBehalf(
        address burnForAddress,
        address from,
        uint amount
    ) external onlySynthetix {
        _requireCanBurnOnBehalf(burnForAddress, from);
        _voluntaryBurnSynths(burnForAddress, amount, false);
    }

    function burnSynthsToTarget(address from) external onlySynthetix {
        _voluntaryBurnSynths(from, 0, true);
    }

    function burnSynthsToTargetOnBehalf(address burnForAddress, address from) external onlySynthetix {
        _requireCanBurnOnBehalf(burnForAddress, from);
        _voluntaryBurnSynths(burnForAddress, 0, true);
    }

    function burnForRedemption(
        address deprecatedSynthProxy,
        address account,
        uint balance
    ) external onlySynthRedeemer {
        ISynth(IProxy(deprecatedSynthProxy).target()).burn(account, balance);
    }

    // SIP-148: Upgraded Liquidation Mechanism
    /// @notice This is where the core internal liquidation logic resides. This function can only be invoked by Synthetix.
    /// @param account The account to be liquidated
    /// @param isSelfLiquidation boolean to determine if this is a forced or self-invoked liquidation
    /// @return uint the total amount of collateral (SNX) to redeem
    /// @return uint the amount of debt (sUSD) to burn in order to fix the account's c-ratio
    function liquidateAccount(address account, bool isSelfLiquidation)
        external
        onlySynthetix
        returns (uint totalRedeemed, uint amountToLiquidate)
    {
        require(liquidator().isLiquidationOpen(account, isSelfLiquidation), "Not open for liquidation");

        // Get the penalty for the liquidation type
        uint penalty = isSelfLiquidation ? getSelfLiquidationPenalty() : getLiquidationPenalty();

        // Get the account's debt balance
        (uint debtBalance, , bool anyRateIsInvalid) =
            _debtBalanceOfAndTotalDebt(synthetixDebtShare().balanceOf(account), sUSD);

        // Get the SNX rate
        (uint snxRate, bool snxRateInvalid) = exchangeRates().rateAndInvalid(SNX);
        _requireRatesNotInvalid(anyRateIsInvalid || snxRateInvalid);

        // Get the total amount of SNX collateral (including escrows and rewards)
        uint collateralForAccount = _collateral(account);

        // Calculate the amount of debt to liquidate to fix c-ratio
        amountToLiquidate = liquidator().calculateAmountToFixCollateral(
            debtBalance,
            _snxToUSD(collateralForAccount, snxRate),
            penalty
        );

        // Get the equivalent amount of SNX for the amount to liquidate
        totalRedeemed = _usdToSnx(amountToLiquidate, snxRate).multiplyDecimal(SafeDecimalMath.unit().add(penalty));

        // The balanceOf here can be considered "transferable" since it's not escrowed,
        // and it is the only SNX that can potentially be transfered if unstaked.
        uint transferableBalance = IERC20(address(synthetix())).balanceOf(account);
        if (totalRedeemed > transferableBalance) {
            // Set totalRedeemed to all transferable collateral.
            // i.e. the value of the account's staking position relative to balanceOf will be unwound.
            totalRedeemed = transferableBalance;

            // Liquidate their debt based on the ratio of their transferable collateral.
            amountToLiquidate = debtBalance.multiplyDecimal(transferableBalance).divideDecimal(collateralForAccount);
        }

        // Reduce debt shares by amount to liquidate.
        _removeFromDebtRegister(account, amountToLiquidate, debtBalance);

        // Remove liquidation flag
        liquidator().removeAccountInLiquidation(account);
    }

    function setCurrentPeriodId(uint128 periodId) external {
        require(msg.sender == address(feePool()), "Must be fee pool");

        ISynthetixDebtShare sds = synthetixDebtShare();

        if (sds.currentPeriodId() < periodId) {
            sds.takeSnapshot(periodId);
        }
    }

    function setLastDebtRatio(uint256 ratio) external onlyOwner {
        lastDebtRatio = ratio;
    }

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

    function _requireRatesNotInvalid(bool anyRateIsInvalid) internal pure {
        require(!anyRateIsInvalid, "A synth or SNX rate is invalid");
    }

    function _requireCanIssueOnBehalf(address issueForAddress, address from) internal view {
        require(delegateApprovals().canIssueFor(issueForAddress, from), "Not approved to act on behalf");
    }

    function _requireCanBurnOnBehalf(address burnForAddress, address from) internal view {
        require(delegateApprovals().canBurnFor(burnForAddress, from), "Not approved to act on behalf");
    }

    function _issueSynths(
        address from,
        uint amount,
        bool issueMax
    ) internal {
        // check breaker
        if (!_verifyCircuitBreaker()) {
            return;
        }

        (uint maxIssuable, , , bool anyRateIsInvalid) = _remainingIssuableSynths(from);
        _requireRatesNotInvalid(anyRateIsInvalid);

        if (!issueMax) {
            require(amount <= maxIssuable, "Amount too large");
        } else {
            amount = maxIssuable;
        }

        // Keep track of the debt they're about to create
        _addToDebtRegister(from, amount);

        // record issue timestamp
        _setLastIssueEvent(from);

        // Create their synths
        synths[sUSD].issue(from, amount);

        // Account for the issued debt in the cache
        debtCache().updateCachedsUSDDebt(SafeCast.toInt256(amount));
    }

    function _burnSynths(
        address debtAccount,
        address burnAccount,
        uint amount,
        uint existingDebt
    ) internal returns (uint amountBurnt) {
        // check breaker
        if (!_verifyCircuitBreaker()) {
            return 0;
        }

        // liquidation requires sUSD to be already settled / not in waiting period

        // If they're trying to burn more debt than they actually owe, rather than fail the transaction, let's just
        // clear their debt and leave them be.
        amountBurnt = existingDebt < amount ? existingDebt : amount;

        // Remove liquidated debt from the ledger
        _removeFromDebtRegister(debtAccount, amountBurnt, existingDebt);

        // synth.burn does a safe subtraction on balance (so it will revert if there are not enough synths).
        synths[sUSD].burn(burnAccount, amountBurnt);

        // Account for the burnt debt in the cache.
        debtCache().updateCachedsUSDDebt(-SafeCast.toInt256(amountBurnt));
    }

    // If burning to target, `amount` is ignored, and the correct quantity of sUSD is burnt to reach the target
    // c-ratio, allowing fees to be claimed. In this case, pending settlements will be skipped as the user
    // will still have debt remaining after reaching their target.
    function _voluntaryBurnSynths(
        address from,
        uint amount,
        bool burnToTarget
    ) internal {
        // check breaker
        if (!_verifyCircuitBreaker()) {
            return;
        }

        if (!burnToTarget) {
            // If not burning to target, then burning requires that the minimum stake time has elapsed.
            require(_canBurnSynths(from), "Minimum stake time not reached");
            // First settle anything pending into sUSD as burning or issuing impacts the size of the debt pool
            (, uint refunded, uint numEntriesSettled) = exchanger().settle(from, sUSD);
            if (numEntriesSettled > 0) {
                amount = exchanger().calculateAmountAfterSettlement(from, sUSD, amount, refunded);
            }
        }

        (uint existingDebt, , bool anyRateIsInvalid) =
            _debtBalanceOfAndTotalDebt(synthetixDebtShare().balanceOf(from), sUSD);
        (uint maxIssuableSynthsForAccount, bool snxRateInvalid) = _maxIssuableSynths(from);
        _requireRatesNotInvalid(anyRateIsInvalid || snxRateInvalid);
        require(existingDebt > 0, "No debt to forgive");

        if (burnToTarget) {
            amount = existingDebt.sub(maxIssuableSynthsForAccount);
        }

        uint amountBurnt = _burnSynths(from, from, amount, existingDebt);

        // Check and remove liquidation if existingDebt after burning is <= maxIssuableSynths
        // Issuance ratio is fixed so should remove any liquidations
        if (existingDebt.sub(amountBurnt) <= maxIssuableSynthsForAccount) {
            liquidator().removeAccountInLiquidation(from);
        }
    }

    function _setLastIssueEvent(address account) internal {
        // Set the timestamp of the last issueSynths
        flexibleStorage().setUIntValue(
            CONTRACT_NAME,
            keccak256(abi.encodePacked(LAST_ISSUE_EVENT, account)),
            block.timestamp
        );
    }

    function _addToDebtRegister(address from, uint amount) internal {
        // important: this has to happen before any updates to user's debt shares
        liquidatorRewards().updateEntry(from);

        ISynthetixDebtShare sds = synthetixDebtShare();

        // it is possible (eg in tests, system initialized with extra debt) to have issued debt without any shares issued
        // in which case, the first account to mint gets the debt. yw.
        uint debtShares = _sharesForDebt(amount);
        if (debtShares == 0) {
            sds.mintShare(from, amount);
        } else {
            sds.mintShare(from, debtShares);
        }
    }

    function _removeFromDebtRegister(
        address from,
        uint debtToRemove,
        uint existingDebt
    ) internal {
        // important: this has to happen before any updates to user's debt shares
        liquidatorRewards().updateEntry(from);

        ISynthetixDebtShare sds = synthetixDebtShare();

        uint currentDebtShare = sds.balanceOf(from);

        if (debtToRemove == existingDebt) {
            sds.burnShare(from, currentDebtShare);
        } else {
            uint sharesToRemove = _sharesForDebt(debtToRemove);
            sds.burnShare(from, sharesToRemove < currentDebtShare ? sharesToRemove : currentDebtShare);
        }
    }

    function _verifyCircuitBreaker() internal returns (bool) {
        (, int256 rawRatio, , , ) =
            AggregatorV2V3Interface(requireAndGetAddress(CONTRACT_EXT_AGGREGATOR_DEBT_RATIO)).latestRoundData();

        uint deviation = _calculateDeviation(lastDebtRatio, uint(rawRatio));

        if (deviation >= getPriceDeviationThresholdFactor()) {
            systemStatus().suspendIssuance(CIRCUIT_BREAKER_SUSPENSION_REASON);
            return false;
        }
        lastDebtRatio = uint(rawRatio);

        return true;
    }

    function _calculateDeviation(uint last, uint fresh) internal pure returns (uint deviation) {
        if (last == 0) {
            deviation = 1;
        } else if (fresh == 0) {
            deviation = uint(-1);
        } else if (last > fresh) {
            deviation = last.divideDecimal(fresh);
        } else {
            deviation = fresh.divideDecimal(last);
        }
    }

    /* ========== MODIFIERS ========== */
    modifier onlySynthetix() {
        require(msg.sender == address(synthetix()), "Issuer: Only the synthetix contract can perform this action");
        _;
    }

    modifier onlyTrustedMinters() {
        require(
            msg.sender == resolver.getAddress(CONTRACT_SYNTHETIXBRIDGETOOPTIMISM) ||
                msg.sender == resolver.getAddress(CONTRACT_SYNTHETIXBRIDGETOBASE),
            "Issuer: Only trusted minters can perform this action"
        );
        _;
    }

    function _onlySynthRedeemer() internal view {
        require(msg.sender == address(synthRedeemer()), "Issuer: Only the SynthRedeemer contract can perform this action");
    }

    modifier onlySynthRedeemer() {
        _onlySynthRedeemer();
        _;
    }

    modifier issuanceActive() {
        _issuanceActive();
        _;
    }

    function _issuanceActive() private {
        systemStatus().requireIssuanceActive();
    }

    modifier synthActive(bytes32 currencyKey) {
        _synthActive(currencyKey);
        _;
    }

    function _synthActive(bytes32 currencyKey) private {
        systemStatus().requireSynthActive(currencyKey);
    }

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

    event SynthAdded(bytes32 currencyKey, address synth);
    event SynthRemoved(bytes32 currencyKey, address synth);
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_resolver","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"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":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"synth","type":"address"}],"name":"SynthAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"synth","type":"address"}],"name":"SynthRemoved","type":"event"},{"constant":true,"inputs":[],"name":"CIRCUIT_BREAKER_SUSPENSION_REASON","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CONTRACT_NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ISynth","name":"synth","type":"address"}],"name":"addSynth","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ISynth[]","name":"synthsToAdd","type":"address[]"}],"name":"addSynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"allNetworksDebtInfo","outputs":[{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"sharesSupply","type":"uint256"},{"internalType":"bool","name":"isStale","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"anySynthOrSNXRateIsInvalid","outputs":[{"internalType":"bool","name":"anyRateInvalid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"availableCurrencyKeys","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"availableSynthCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"availableSynths","outputs":[{"internalType":"contract ISynth","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"deprecatedSynthProxy","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"burnForRedemption","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnSynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"burnForAddress","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnSynthsOnBehalf","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"burnSynthsToTarget","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"burnForAddress","type":"address"},{"internalType":"address","name":"from","type":"address"}],"name":"burnSynthsToTargetOnBehalf","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnSynthsWithoutDebt","outputs":[{"internalType":"bool","name":"rateInvalid","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"canBurnSynths","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"collateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_issuer","type":"address"}],"name":"collateralisationRatio","outputs":[{"internalType":"uint256","name":"cratio","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_issuer","type":"address"}],"name":"collateralisationRatioAndAnyRatesInvalid","outputs":[{"internalType":"uint256","name":"cratio","type":"uint256"},{"internalType":"bool","name":"anyRateIsInvalid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_issuer","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"debtBalanceOf","outputs":[{"internalType":"uint256","name":"debtBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"getSynths","outputs":[{"internalType":"contract ISynth[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"issuanceRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"issueMaxSynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"issueForAddress","type":"address"},{"internalType":"address","name":"from","type":"address"}],"name":"issueMaxSynthsOnBehalf","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"issueSynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"issueForAddress","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"issueSynthsOnBehalf","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"issueSynthsWithoutDebt","outputs":[{"internalType":"bool","name":"rateInvalid","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"lastDebtRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lastIssueEvent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isSelfLiquidation","type":"bool"}],"name":"liquidateAccount","outputs":[{"internalType":"uint256","name":"totalRedeemed","type":"uint256"},{"internalType":"uint256","name":"amountToLiquidate","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_issuer","type":"address"}],"name":"maxIssuableSynths","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minimumStakeTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_issuer","type":"address"}],"name":"remainingIssuableSynths","outputs":[{"internalType":"uint256","name":"maxIssuable","type":"uint256"},{"internalType":"uint256","name":"alreadyIssued","type":"uint256"},{"internalType":"uint256","name":"totalSystemDebt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"removeSynth","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"removeSynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint128","name":"periodId","type":"uint128"}],"name":"setCurrentPeriodId","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"ratio","type":"uint256"}],"name":"setLastDebtRatio","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"synths","outputs":[{"internalType":"contract ISynth","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"synthsByAddress","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"bool","name":"excludeOtherCollateral","type":"bool"}],"name":"totalIssuedSynths","outputs":[{"internalType":"uint256","name":"totalIssued","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"transferableSynthetixAndAnyRateIsInvalid","outputs":[{"internalType":"uint256","name":"transferable","type":"uint256"},{"internalType":"bool","name":"anyRateIsInvalid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b5060405162005dbf38038062005dbf8339810160408190526200003491620000fc565b8080836001600160a01b038116620000695760405162461bcd60e51b81526004016200006090620001b8565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91620000b691849062000192565b60405180910390a150600280546001600160a01b0319166001600160a01b03929092169190911790555062000213915050565b8051620000f681620001f9565b92915050565b600080604083850312156200011057600080fd5b60006200011e8585620000e9565b92505060206200013185828601620000e9565b9150509250929050565b6200014681620001e5565b82525050565b6200014681620001d3565b600062000166601983620001ca565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b60408101620001a282856200013b565b620001b160208301846200014c565b9392505050565b60208082528101620000f68162000157565b90815260200190565b60006001600160a01b038216620000f6565b6000620000f6826000620000f682620001d3565b6200020481620001d3565b81146200021057600080fd5b50565b615b9c80620002236000396000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c80637168d2c211610182578063a311c7c2116100e9578063c81ff8fa116100a2578063d686c06c1161007c578063d686c06c14610605578063dbf6334014610618578063dd3d2b2e14610620578063fd864ccf14610633576102bb565b8063c81ff8fa146105cc578063c8977132146105df578063d37c4d8b146105f2576102bb565b8063a311c7c214610565578063a5fdc5de14610578578063ae3bbbbb1461058b578063b06e8c651461059e578063b410a034146105b1578063bff4fdfc146105b9576102bb565b8063835e119c1161013b578063835e119c14610509578063849cf5881461051c578063890235d41461052f578063899ffef4146105425780638da5cb5b1461054a5780639a5154b414610552576102bb565b80637168d2c21461049d57806372c65816146104b057806372cb051f146104d157806374185360146104e657806379ba5097146104ee5780637b1001b7146104f6576102bb565b806331e6da5a1161022657806347a9b6db116101df57806347a9b6db14610431578063497d704a146104445780634e99bda91461045757806353a47bb71461045f578063614d08f8146104745780636bed04151461047c576102bb565b806331e6da5a146103bd57806332608039146103d05780633b6afe40146103e35780633fa70f451461040357806344ec6b621461040b578063461ee7631461041e576102bb565b806314d494131161027857806314d494131461035f5780631627540c1461036757806316b2213f1461037a578063242df9e11461038d5780632af64bd3146103955780632b3f41aa146103aa576102bb565b8063042e0688146102c057806304f3bcec146102d557806305b3c1c9146102f35780630b887dae146103135780631137aedf146103265780631313e6ca14610348575b600080fd5b6102d36102ce366004614af4565b610646565b005b6102dd6106b7565b6040516102ea9190615821565b60405180910390f35b610306610301366004614a01565b6106c6565b6040516102ea919061576d565b6102d3610321366004614bcb565b6106da565b610339610334366004614a01565b6107b8565b6040516102ea93929190615797565b6103506107d4565b6040516102ea939291906159ea565b610306610968565b6102d3610375366004614a01565b61096e565b610306610388366004614a01565b6109cc565b6103066109de565b61039d6109ee565b6040516102ea919061575f565b6102d36103b8366004614a3d565b610b05565b6102d36103cb366004614c83565b610b54565b6102dd6103de366004614bcb565b610c84565b6103f66103f1366004614b24565b610c9f565b6040516102ea919061574e565b610306610d4d565b6102d3610419366004614a77565b610d52565b6102d361042c366004614bcb565b610da5565b6102d361043f366004614b24565b610db2565b6102d3610452366004614a01565b610e63565b61039d610eab565b610467610f3d565b6040516102ea919061567a565b610306610f4c565b61048f61048a366004614af4565b610f59565b6040516102ea9291906159dc565b6102d36104ab366004614b24565b61103f565b6104c36104be366004614ac4565b611174565b6040516102ea929190615789565b6104d9611622565b6040516102ea919061573d565b6102d361162e565b6102d3611780565b610306610504366004614c28565b61181c565b6102dd610517366004614bcb565b611828565b6102d361052a366004614c47565b61184f565b61039d61053d366004614c07565b6118c9565b6104d9611c28565b610467611ef7565b6102d3610560366004614a77565b611f06565b610306610573366004614a01565b611f54565b610306610586366004614a01565b611f66565b61048f610599366004614a01565b611f71565b6102d36105ac366004614af4565b611f87565b610306611fcb565b61039d6105c7366004614a01565b611fd5565b61039d6105da366004614c07565b611fe0565b6102d36105ed366004614a01565b612380565b610306610600366004614af4565b6123c5565b6102d3610613366004614a77565b612478565b61030661251e565b61030661062e366004614a01565b612524565b6102d3610641366004614a3d565b61252f565b61064e61257e565b6001600160a01b0316336001600160a01b0316146106875760405162461bcd60e51b815260040161067e906158ce565b60405180910390fd5b600081116106a75760405162461bcd60e51b815260040161067e9061596e565b6106b382826000612595565b5050565b6002546001600160a01b031681565b6000806106d283612709565b509392505050565b6106e26127d5565b60006106ec612801565b604051636b42ba1d60e11b81529091506001600160a01b0382169063d685743a9061071e9085906000906004016157bf565b600060405180830381600087803b15801561073857600080fd5b505af115801561074c573d6000803e3d6000fd5b50506040516304bd11e560e01b81526001600160a01b03841692506304bd11e5915061077d9060019060040161575f565b600060405180830381600087803b15801561079757600080fd5b505af11580156107ab573d6000803e3d6000fd5b505050506106b382612818565b60008060006107c684612cd8565b509196909550909350915050565b60008060008060006108057f6578743a41676772656761746f7249737375656453796e746873000000000000612d65565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561083d57600080fd5b505afa158015610851573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108759190810190614d82565b509350509250506000806108a2766578743a41676772656761746f7244656274526174696f60481b612d65565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156108da57600080fd5b505afa1580156108ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109129190810190614d82565b509350509250508396508160001461093957610934878363ffffffff612dc216565b61093c565b60005b955082610947612ddb565b4203118061095d575080610959612ddb565b4203115b945050505050909192565b60075481565b6109766127d5565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906109c190839061567a565b60405180910390a150565b60066020526000908152604090205481565b60006109e8612e85565b90505b90565b600060606109fa611c28565b905060005b8151811015610afc576000828281518110610a1657fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a72190610a6790859060040161576d565b60206040518083038186803b158015610a7f57600080fd5b505afa158015610a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ab79190810190614a1f565b6001600160a01b0316141580610ae257506000818152600360205260409020546001600160a01b0316155b15610af357600093505050506109eb565b506001016109ff565b50600191505090565b610b0d61257e565b6001600160a01b0316336001600160a01b031614610b3d5760405162461bcd60e51b815260040161067e906158ce565b610b478282612ee0565b6106b38260006001612f81565b610b5c6131f1565b6001600160a01b0316336001600160a01b031614610b8c5760405162461bcd60e51b815260040161067e906158de565b6000610b96613206565b9050816001600160801b0316816001600160a01b031663988e65956040518163ffffffff1660e01b815260040160206040518083038186803b158015610bdb57600080fd5b505afa158015610bef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c139190810190614ca1565b6001600160801b031610156106b35760405163abb6de9560e01b81526001600160a01b0382169063abb6de9590610c4e9085906004016159ce565b600060405180830381600087803b158015610c6857600080fd5b505af1158015610c7c573d6000803e3d6000fd5b505050505050565b6005602052600090815260409020546001600160a01b031681565b60408051828152602080840282010190915260609082908290828015610ccf578160200160208202803883390190505b50905060005b82811015610d425760056000878784818110610ced57fe5b90506020020135815260200190815260200160002060009054906101000a90046001600160a01b0316828281518110610d2257fe5b6001600160a01b0390921660209283029190910190910152600101610cd5565b509150505b92915050565b60a581565b610d5a61257e565b6001600160a01b0316336001600160a01b031614610d8a5760405162461bcd60e51b815260040161067e906158ce565b610d948383613226565b610da083826000612595565b505050565b610dad6127d5565b600755565b610dba6127d5565b8060005b81811015610df757610def848483818110610dd557fe5b9050602002016020610dea9190810190614c47565b61325b565b600101610dbe565b50610e00612801565b6001600160a01b03166304bd11e560016040518263ffffffff1660e01b8152600401610e2c919061575f565b600060405180830381600087803b158015610e4657600080fd5b505af1158015610e5a573d6000803e3d6000fd5b50505050505050565b610e6b61257e565b6001600160a01b0316336001600160a01b031614610e9b5760405162461bcd60e51b815260040161067e906158ce565b610ea88160006001612f81565b50565b6000610eb56133ec565b6001600160a01b031663c8e5bbd5610ecd6001613407565b6040518263ffffffff1660e01b8152600401610ee9919061573d565b60006040518083038186803b158015610f0157600080fd5b505afa158015610f15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d479190810190614b66565b6001546001600160a01b031681565b6524b9b9bab2b960d11b81565b6000806000610ff0610f69613206565b6001600160a01b03166370a08231876040518263ffffffff1660e01b8152600401610f94919061567a565b60206040518083038186803b158015610fac57600080fd5b505afa158015610fc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610fe49190810190614be9565b620a69cb60eb1b6134e3565b9350909150600090506110116110046135cd565b839063ffffffff61362516565b90508481106110235760009350611036565b611033858263ffffffff61363a16565b93505b50509250929050565b6110476127d5565b806000611052612801565b9050606082604051908082528060200260200182016040528015611080578160200160208202803883390190505b506040516305ece36d60e21b81529091506001600160a01b038316906317b38db4906110b490889088908690600401615717565b600060405180830381600087803b1580156110ce57600080fd5b505af11580156110e2573d6000803e3d6000fd5b50506040516304bd11e560e01b81526001600160a01b03851692506304bd11e591506111139060019060040161575f565b600060405180830381600087803b15801561112d57600080fd5b505af1158015611141573d6000803e3d6000fd5b506000925050505b83811015610c7c5761116c86868381811061116057fe5b90506020020135612818565b600101611149565b60008061117f61257e565b6001600160a01b0316336001600160a01b0316146111af5760405162461bcd60e51b815260040161067e906158ce565b6111b7613662565b6001600160a01b031663952225f385856040518363ffffffff1660e01b81526004016111e49291906156a3565b60206040518083038186803b1580156111fc57600080fd5b505afa158015611210573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112349190810190614bad565b6112505760405162461bcd60e51b815260040161067e9061591e565b6000836112645761125f61367a565b61126c565b61126c6136d7565b905060008061130461127c613206565b6001600160a01b03166370a08231896040518263ffffffff1660e01b81526004016112a7919061567a565b60206040518083038186803b1580156112bf57600080fd5b505afa1580156112d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112f79190810190614be9565b631cd554d160e21b6134e3565b92505091506000806113146133ec565b6001600160a01b0316630c71cd23620a69cb60eb1b6040518263ffffffff1660e01b8152600401611345919061576d565b604080518083038186803b15801561135c57600080fd5b505afa158015611370573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113949190810190614cbf565b915091506113a983806113a45750815b613738565b60006113b48a613756565b90506113be613662565b6001600160a01b031663f557f73c866113d784876138ff565b896040518463ffffffff1660e01b81526004016113f693929190615797565b60206040518083038186803b15801561140e57600080fd5b505afa158015611422573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114469190810190614be9565b96506114ed6114d787731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561149357600080fd5b505af41580156114a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114cb9190810190614be9565b9063ffffffff61391116565b6114e18986613936565b9063ffffffff61394816565b975060006114f961257e565b6001600160a01b03166370a082318c6040518263ffffffff1660e01b8152600401611524919061567a565b60206040518083038186803b15801561153c57600080fd5b505afa158015611550573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115749190810190614be9565b9050808911156115a4579750876115a182611595888463ffffffff61394816565b9063ffffffff61397216565b97505b6115af8b898861399c565b6115b7613662565b6001600160a01b031663974e9e7f8c6040518263ffffffff1660e01b81526004016115e2919061567a565b600060405180830381600087803b1580156115fc57600080fd5b505af1158015611610573d6000803e3d6000fd5b50505050505050505050509250929050565b60606109e86000613407565b6060611638611c28565b905060005b81518110156106b357600082828151811061165457fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001611696919061566f565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016116c29291906157da565b60206040518083038186803b1580156116da57600080fd5b505afa1580156116ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117129190810190614a1f565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa689061176e908490849061577b565b60405180910390a1505060010161163d565b6001546001600160a01b031633146117aa5760405162461bcd60e51b815260040161067e9061584e565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c926117ed926001600160a01b0391821692911690615688565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60006106d28383613b7d565b6004818154811061183557fe5b6000918252602090912001546001600160a01b0316905081565b6118576127d5565b6118608161325b565b611868612801565b6001600160a01b03166304bd11e560016040518263ffffffff1660e01b8152600401611894919061575f565b600060405180830381600087803b1580156118ae57600080fd5b505af11580156118c2573d6000803e3d6000fd5b5050505050565b6002546040516321f8a72160e01b81526000916001600160a01b0316906321f8a72190611916907853796e746865746978427269646765546f4f7074696d69736d60381b9060040161576d565b60206040518083038186803b15801561192e57600080fd5b505afa158015611942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119669190810190614a1f565b6001600160a01b0316336001600160a01b03161480611a2d57506002546040516321f8a72160e01b81526001600160a01b03909116906321f8a721906119c8907453796e746865746978427269646765546f4261736560581b9060040161576d565b60206040518083038186803b1580156119e057600080fd5b505afa1580156119f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a189190810190614a1f565b6001600160a01b0316336001600160a01b0316145b611a495760405162461bcd60e51b815260040161067e9061597e565b6000848152600560205260409020546001600160a01b0316611a7d5760405162461bcd60e51b815260040161067e9061599e565b60008211611a9d5760405162461bcd60e51b815260040161067e9061596e565b611aa683613d88565b6000848152600560205260409081902054905163219e412d60e21b81526001600160a01b039091169063867904b490611ae590869086906004016156be565b600060405180830381600087803b158015611aff57600080fd5b505af1158015611b13573d6000803e3d6000fd5b50505050600080611b226133ec565b6001600160a01b0316630c71cd23876040518263ffffffff1660e01b8152600401611b4d919061576d565b604080518083038186803b158015611b6457600080fd5b505afa158015611b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b9c9190810190614cbf565b91509150611ba8612801565b6001600160a01b03166342c7b819611bce611bc9878663ffffffff61394816565b613e01565b6040518263ffffffff1660e01b8152600401611bea919061576d565b600060405180830381600087803b158015611c0457600080fd5b505af1158015611c18573d6000803e3d6000fd5b50929450505050505b9392505050565b606080611c33613e2a565b60408051600f808252610200820190925291925060609190602082016101e080388339019050509050680a6f2dce8d0cae8d2f60bb1b81600081518110611c7657fe5b6020026020010181815250506822bc31b430b733b2b960b91b81600181518110611c9c57fe5b6020026020010181815250506c45786368616e6765526174657360981b81600281518110611cc657fe5b6020026020010181815250507153796e74686574697844656274536861726560701b81600381518110611cf557fe5b60200260200101818152505066119959541bdbdb60ca1b81600481518110611d1957fe5b6020026020010181815250507044656c6567617465417070726f76616c7360781b81600581518110611d4757fe5b6020026020010181815250506d2932bbb0b93222b9b1b937bbab1960911b81600681518110611d7257fe5b6020026020010181815250506e53796e746865746978457363726f7760881b81600781518110611d9e57fe5b602002602001018181525050692634b8bab4b230ba37b960b11b81600881518110611dc557fe5b602002602001018181525050704c697175696461746f725265776172647360781b81600981518110611df357fe5b6020026020010181815250506844656274436163686560b81b81600a81518110611e1957fe5b6020026020010181815250506c29bcb73a342932b232b2b6b2b960991b81600b81518110611e4357fe5b6020026020010181815250506b53797374656d53746174757360a01b81600c81518110611e6c57fe5b6020026020010181815250507f6578743a41676772656761746f7249737375656453796e74687300000000000081600d81518110611ea657fe5b602002602001018181525050766578743a41676772656761746f7244656274526174696f60481b81600e81518110611eda57fe5b602002602001018181525050611ef08282613e7b565b9250505090565b6000546001600160a01b031681565b611f0e61257e565b6001600160a01b0316336001600160a01b031614611f3e5760405162461bcd60e51b815260040161067e906158ce565b611f488383612ee0565b610da083826000612f81565b6000611f5f82613f30565b5092915050565b6000610d4782613756565b600080611f7d83613f30565b915091505b915091565b611f8f61257e565b6001600160a01b0316336001600160a01b031614611fbf5760405162461bcd60e51b815260040161067e906158ce565b6106b382826000612f81565b60006109e86135cd565b6000610d4782613fb0565b6002546040516321f8a72160e01b81526000916001600160a01b0316906321f8a7219061202d907853796e746865746978427269646765546f4f7074696d69736d60381b9060040161576d565b60206040518083038186803b15801561204557600080fd5b505afa158015612059573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061207d9190810190614a1f565b6001600160a01b0316336001600160a01b0316148061214457506002546040516321f8a72160e01b81526001600160a01b03909116906321f8a721906120df907453796e746865746978427269646765546f4261736560581b9060040161576d565b60206040518083038186803b1580156120f757600080fd5b505afa15801561210b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061212f9190810190614a1f565b6001600160a01b0316336001600160a01b0316145b6121605760405162461bcd60e51b815260040161067e9061597e565b6000848152600560205260409020546001600160a01b03166121945760405162461bcd60e51b815260040161067e9061599e565b600082116121b45760405162461bcd60e51b815260040161067e9061596e565b6121bc613fcf565b6001600160a01b0316631b16802c84866040518363ffffffff1660e01b81526004016121e99291906156be565b606060405180830381600087803b15801561220357600080fd5b505af1158015612217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061223b9190810190614d3f565b50505060008481526005602052604090819020549051632770a7eb60e21b81526001600160a01b0390911690639dc29fac9061227d90869086906004016156be565b600060405180830381600087803b15801561229757600080fd5b505af11580156122ab573d6000803e3d6000fd5b505050506000806122ba6133ec565b6001600160a01b0316630c71cd23876040518263ffffffff1660e01b81526004016122e5919061576d565b604080518083038186803b1580156122fc57600080fd5b505afa158015612310573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123349190810190614cbf565b91509150612340612801565b6001600160a01b03166342c7b819612361611bc9878663ffffffff61394816565b6000036040518263ffffffff1660e01b8152600401611bea919061576d565b61238861257e565b6001600160a01b0316336001600160a01b0316146123b85760405162461bcd60e51b815260040161067e906158ce565b610ea88160006001612595565b6000806123d0613206565b90506000816001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401612400919061567a565b60206040518083038186803b15801561241857600080fd5b505afa15801561242c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124509190810190614be9565b90508061246257600092505050610d47565b61246c81856134e3565b50909695505050505050565b612480613fe6565b826001600160a01b031663d4b839926040518163ffffffff1660e01b815260040160206040518083038186803b1580156124b957600080fd5b505afa1580156124cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124f19190810190614a1f565b6001600160a01b0316639dc29fac83836040518363ffffffff1660e01b8152600401610e2c9291906156be565b60045490565b6000610d478261401e565b61253761257e565b6001600160a01b0316336001600160a01b0316146125675760405162461bcd60e51b815260040161067e906158ce565b6125718282613226565b6106b38260006001612595565b60006109e8680a6f2dce8d0cae8d2f60bb1b612d65565b61259d6140e7565b6125a657610da0565b6000806125b285612cd8565b9350505091506125c181613738565b826125eb57818411156125e65760405162461bcd60e51b815260040161067e9061589e565b6125ef565b8193505b6125f9858561421c565b61260285613d88565b631cd554d160e21b60005260056020527f74c62d09fbc50aefae0794a9a068f786a692826fbdfe63828ec23a875865823f5460405163219e412d60e21b81526001600160a01b039091169063867904b49061266390889088906004016156be565b600060405180830381600087803b15801561267d57600080fd5b505af1158015612691573d6000803e3d6000fd5b5050505061269d612801565b6001600160a01b03166342c7b8196126b486613e01565b6040518263ffffffff1660e01b81526004016126d0919061576d565b600060405180830381600087803b1580156126ea57600080fd5b505af11580156126fe573d6000803e3d6000fd5b505050505050505050565b6000806000806127176133ec565b6001600160a01b0316630c71cd23620a69cb60eb1b6040518263ffffffff1660e01b8152600401612748919061576d565b604080518083038186803b15801561275f57600080fd5b505afa158015612773573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127979190810190614cbf565b9150915060006127af6127a987613756565b846138ff565b90506127c96127bc6135cd565b829063ffffffff61394816565b94509092505050915091565b6000546001600160a01b031633146127ff5760405162461bcd60e51b815260040161067e9061592e565b565b60006109e86844656274436163686560b81b612d65565b6000818152600560205260409020546001600160a01b03168061284d5760405162461bcd60e51b815260040161067e906158fe565b631cd554d160e21b8214156128745760405162461bcd60e51b815260040161067e9061595e565b6000816001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128af57600080fd5b505afa1580156128c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128e79190810190614be9565b90508015612b7b576000806128fa6133ec565b6001600160a01b0316638295016a86856040518363ffffffff1660e01b81526004016129279291906157fa565b60606040518083038186803b15801561293f57600080fd5b505afa158015612953573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129779190810190614d3f565b50915091506000811161299c5760405162461bcd60e51b815260040161067e9061590e565b60006129a6614366565b631cd554d160e21b60005260056020527f74c62d09fbc50aefae0794a9a068f786a692826fbdfe63828ec23a875865823f5460405163219e412d60e21b81529192506001600160a01b03169063867904b490612a0890849087906004016156be565b600060405180830381600087803b158015612a2257600080fd5b505af1158015612a36573d6000803e3d6000fd5b50505050612a42612801565b6001600160a01b03166342c7b819612a5985613e01565b6040518263ffffffff1660e01b8152600401612a75919061576d565b600060405180830381600087803b158015612a8f57600080fd5b505af1158015612aa3573d6000803e3d6000fd5b50505050806001600160a01b0316633a70599c866001600160a01b031663ec5568896040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612b279190810190614c65565b846040518363ffffffff1660e01b8152600401612b4592919061582f565b600060405180830381600087803b158015612b5f57600080fd5b505af1158015612b73573d6000803e3d6000fd5b505050505050505b60005b600454811015612c6257826001600160a01b031660048281548110612b9f57fe5b6000918252602090912001546001600160a01b03161415612c5a5760048181548110612bc757fe5b600091825260209091200180546001600160a01b0319169055600480546000198101908110612bf257fe5b600091825260209091200154600480546001600160a01b039092169183908110612c1857fe5b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556004805490612c5490600019830161488e565b50612c62565b600101612b7e565b506001600160a01b038216600090815260066020908152604080832083905585835260059091529081902080546001600160a01b0319169055517f6166f5c475cc1cd535c6cdf14a6d5edb811e34117031fc2863392a136eb655d090612ccb908590859061577b565b60405180910390a1505050565b600080600080612d14612ce9613206565b6001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016112a7919061567a565b91945092509050600080612d2787612709565b915091508195508280612d375750805b9250858510612d495760009550612d5c565b612d59868663ffffffff61363a16565b95505b50509193509193565b60008181526003602090815260408083205490516001600160a01b039091169182151591612d959186910161564f565b60405160208183030381529060405290611f5f5760405162461bcd60e51b815260040161067e919061583d565b6000611c2183836b033b2e3c9fd0803ce8000000614381565b6000612de56143b9565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6e1c985d1954dd185b1954195c9a5bd9608a1b6040518363ffffffff1660e01b8152600401612e35929190615789565b60206040518083038186803b158015612e4d57600080fd5b505afa158015612e61573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109e89190810190614be9565b6000612e8f6143b9565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6f6d696e696d756d5374616b6554696d6560801b6040518363ffffffff1660e01b8152600401612e35929190615789565b612ee86143d6565b6001600160a01b0316637d3f0ba283836040518363ffffffff1660e01b8152600401612f15929190615688565b60206040518083038186803b158015612f2d57600080fd5b505afa158015612f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f659190810190614bad565b6106b35760405162461bcd60e51b815260040161067e9061585e565b612f896140e7565b612f9257610da0565b806130ef57612fa083613fb0565b612fbc5760405162461bcd60e51b815260040161067e906159ae565b600080612fc7613fcf565b6001600160a01b0316631b16802c86631cd554d160e21b6040518363ffffffff1660e01b8152600401612ffb9291906156be565b606060405180830381600087803b15801561301557600080fd5b505af1158015613029573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061304d9190810190614d3f565b90935091505080156130ec57613061613fcf565b6001600160a01b0316634c268fc886631cd554d160e21b87866040518563ffffffff1660e01b815260040161309994939291906156d9565b60206040518083038186803b1580156130b157600080fd5b505afa1580156130c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130e99190810190614be9565b93505b50505b6000806130fd612ce9613206565b925050915060008061310e87612709565b9150915061312283806113a4575081613738565b600084116131425760405162461bcd60e51b815260040161067e9061588e565b841561315b57613158848363ffffffff61363a16565b95505b6000613169888989886143f5565b90508261317c868363ffffffff61363a16565b116131e757613189613662565b6001600160a01b031663974e9e7f896040518263ffffffff1660e01b81526004016131b4919061567a565b600060405180830381600087803b1580156131ce57600080fd5b505af11580156131e2573d6000803e3d6000fd5b505050505b5050505050505050565b60006109e866119959541bdbdb60ca1b612d65565b60006109e87153796e74686574697844656274536861726560701b612d65565b61322e6143d6565b6001600160a01b0316630487261783836040518363ffffffff1660e01b8152600401612f15929190615688565b6000816001600160a01b031663dbd06c856040518163ffffffff1660e01b815260040160206040518083038186803b15801561329657600080fd5b505afa1580156132aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506132ce9190810190614be9565b6000818152600560205260409020549091506001600160a01b0316156133065760405162461bcd60e51b815260040161067e9061598e565b6001600160a01b0382166000908152600660205260409020541561333c5760405162461bcd60e51b815260040161067e9061593e565b60048054600181019091557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0180546001600160a01b0384166001600160a01b03199182168117909255600083815260056020908152604080832080549094168517909355928152600690925290819020829055517f0a2b6ebf143b3e9fcd67e17748ad315174746100c27228468b2c98c302c62884906133e0908390859061577b565b60405180910390a15050565b60006109e86c45786368616e6765526174657360981b612d65565b60608082613416576000613419565b60015b60ff166004805490500160405190808252806020026020018201604052801561344c578160200160208202803883390190505b50905060005b6004548110156134b357600660006004838154811061346d57fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205482518390839081106134a057fe5b6020908102919091010152600101613452565b508215610d47576004548151620a69cb60eb1b91839181106134d157fe5b60200260200101818152505092915050565b60008060008060006134f36107d4565b9250509150866000141561350f576000945090925090506135c6565b60008061351a6133ec565b6001600160a01b0316630c71cd23896040518263ffffffff1660e01b8152600401613545919061576d565b604080518083038186803b15801561355c57600080fd5b505afa158015613570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506135949190810190614cbf565b915091506135b1826135a58b614533565b9063ffffffff61362516565b965083955080806135bf5750825b9450505050505b9250925092565b60006135d76143b9565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6c69737375616e6365526174696f60981b6040518363ffffffff1660e01b8152600401612e35929190615789565b6000611c218383670de0b6b3a7640000614381565b60008282111561365c5760405162461bcd60e51b815260040161067e906158ae565b50900390565b60006109e8692634b8bab4b230ba37b960b11b612d65565b60006136846143b9565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b716c69717569646174696f6e50656e616c747960701b6040518363ffffffff1660e01b8152600401612e35929190615789565b60006136e16143b9565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7573656c664c69717569646174696f6e50656e616c747960501b6040518363ffffffff1660e01b8152600401612e35929190615789565b8015610ea85760405162461bcd60e51b815260040161067e906158ee565b60008061376161257e565b6001600160a01b03166370a08231846040518263ffffffff1660e01b815260040161378c919061567a565b60206040518083038186803b1580156137a457600080fd5b505afa1580156137b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137dc9190810190614be9565b905060006137e86145e2565b6001600160a01b03161461388c576138896138016145e2565b6001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161382c919061567a565b60206040518083038186803b15801561384457600080fd5b505afa158015613858573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061387c9190810190614be9565b829063ffffffff61391116565b90505b60006138966145ff565b6001600160a01b0316146138b2576138af6138016145ff565b90505b60006138bc61461b565b6001600160a01b031614610d4757611c216138d561461b565b6001600160a01b0316628cc262856040518263ffffffff1660e01b815260040161382c919061567a565b6000611c21838363ffffffff61463a16565b600082820183811015611c215760405162461bcd60e51b815260040161067e9061586e565b6000611c21838363ffffffff61362516565b6000670de0b6b3a7640000613963848463ffffffff61464f16565b8161396a57fe5b049392505050565b6000611c218261399085670de0b6b3a764000063ffffffff61464f16565b9063ffffffff61468916565b6139a461461b565b6001600160a01b031663270fb338846040518263ffffffff1660e01b81526004016139cf919061567a565b600060405180830381600087803b1580156139e957600080fd5b505af11580156139fd573d6000803e3d6000fd5b505050506000613a0b613206565b90506000816001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401613a3b919061567a565b60206040518083038186803b158015613a5357600080fd5b505afa158015613a67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613a8b9190810190614be9565b905082841415613afa57604051631a378f0d60e01b81526001600160a01b03831690631a378f0d90613ac390889085906004016156be565b600060405180830381600087803b158015613add57600080fd5b505af1158015613af1573d6000803e3d6000fd5b505050506118c2565b6000613b05856146be565b9050826001600160a01b0316631a378f0d87848410613b245784613b26565b835b6040518363ffffffff1660e01b8152600401613b439291906156be565b600060405180830381600087803b158015613b5d57600080fd5b505af1158015613b71573d6000803e3d6000fd5b50505050505050505050565b6000806000806000613b8d612801565b6001600160a01b0316633a900a2e6040518163ffffffff1660e01b815260040160806040518083038186803b158015613bc557600080fd5b505afa158015613bd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613bfd9190810190614cde565b935093505092508180613c0d5750805b93506000613c196133ec565b905086613cbf57600080613c2b612801565b6001600160a01b0316632992dba26040518163ffffffff1660e01b8152600401604080518083038186803b158015613c6257600080fd5b505afa158015613c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613c9a9190810190614cbf565b9092509050613caf868363ffffffff61391116565b95508680613cba5750805b965050505b631cd554d160e21b881415613cda5750919350613d81915050565b600080826001600160a01b0316630c71cd238b6040518263ffffffff1660e01b8152600401613d09919061576d565b604080518083038186803b158015613d2057600080fd5b505afa158015613d34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613d589190810190614cbf565b9092509050613d6d868363ffffffff61362516565b8780613d765750815b975097505050505050505b9250929050565b613d906143b9565b6001600160a01b0316631d5b277f6524b9b9bab2b960d11b6d1b185cdd125cdcdd59515d995b9d60921b84604051602001613dcc929190615629565b60405160208183030381529060405280519060200120426040518463ffffffff1660e01b815260040161189493929190615797565b6000600160ff1b8210613e265760405162461bcd60e51b815260040161067e906159be565b5090565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b81600081518110613e6c57fe5b60200260200101818152505090565b60608151835101604051908082528060200260200182016040528015613eab578160200160208202803883390190505b50905060005b8351811015613eed57838181518110613ec657fe5b6020026020010151828281518110613eda57fe5b6020908102919091010152600101613eb1565b5060005b8251811015611f5f57828181518110613f0657fe5b6020026020010151828286510181518110613f1d57fe5b6020908102919091010152600101613ef1565b6000806000613f3e84613756565b9050600080613f79613f4e613206565b6001600160a01b03166370a08231886040518263ffffffff1660e01b8152600401610f94919061567a565b92505091508260001415613f9557600094509250611f82915050565b613fa5828463ffffffff61362516565b945092505050915091565b6000613fc6613fbd612e85565b6114cb8461401e565b42101592915050565b60006109e86822bc31b430b733b2b960b91b612d65565b613fee614366565b6001600160a01b0316336001600160a01b0316146127ff5760405162461bcd60e51b815260040161067e9061587e565b60006140286143b9565b6001600160a01b03166323257c2b6524b9b9bab2b960d11b6d1b185cdd125cdcdd59515d995b9d60921b85604051602001614064929190615629565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b8152600401614097929190615789565b60206040518083038186803b1580156140af57600080fd5b505afa1580156140c3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d479190810190614be9565b60008061410d766578743a41676772656761746f7244656274526174696f60481b612d65565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561414557600080fd5b505afa158015614159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061417d9190810190614d82565b505050915050600061419160075483614780565b905061419b6147cc565b8110614212576141a9614834565b6001600160a01b031663396e258e60a56040518263ffffffff1660e01b81526004016141d5919061576d565b600060405180830381600087803b1580156141ef57600080fd5b505af1158015614203573d6000803e3d6000fd5b505050506000925050506109eb565b5060075550600190565b61422461461b565b6001600160a01b031663270fb338836040518263ffffffff1660e01b815260040161424f919061567a565b600060405180830381600087803b15801561426957600080fd5b505af115801561427d573d6000803e3d6000fd5b50505050600061428b613206565b90506000614298836146be565b90508061430457604051636178258560e11b81526001600160a01b0383169063c2f04b0a906142cd90879087906004016156be565b600060405180830381600087803b1580156142e757600080fd5b505af11580156142fb573d6000803e3d6000fd5b50505050614360565b604051636178258560e11b81526001600160a01b0383169063c2f04b0a9061433290879085906004016156be565b600060405180830381600087803b15801561434c57600080fd5b505af11580156131e7573d6000803e3d6000fd5b50505050565b60006109e86c29bcb73a342932b232b2b6b2b960991b612d65565b60008061439b8461399087600a870263ffffffff61464f16565b90506005600a825b06106143ad57600a015b600a9004949350505050565b60006109e86e466c657869626c6553746f7261676560881b612d65565b60006109e87044656c6567617465417070726f76616c7360781b612d65565b60006143ff6140e7565b61440b5750600061452b565b828210614418578261441a565b815b905061442785828461399c565b631cd554d160e21b60005260056020527f74c62d09fbc50aefae0794a9a068f786a692826fbdfe63828ec23a875865823f54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac9061448890879085906004016156be565b600060405180830381600087803b1580156144a257600080fd5b505af11580156144b6573d6000803e3d6000fd5b505050506144c2612801565b6001600160a01b03166342c7b8196144d983613e01565b6000036040518263ffffffff1660e01b81526004016144f8919061576d565b600060405180830381600087803b15801561451257600080fd5b505af1158015614526573d6000803e3d6000fd5b505050505b949350505050565b600080614559766578743a41676772656761746f7244656274526174696f60481b612d65565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561459157600080fd5b505afa1580156145a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506145c99190810190614d82565b505050915050611c21818461484e90919063ffffffff16565b60006109e86e53796e746865746978457363726f7760881b612d65565b60006109e86d2932bbb0b93222b9b1b937bbab1960911b612d65565b60006109e8704c697175696461746f725265776172647360781b612d65565b6000611c218383670de0b6b3a7640000614863565b60008261465e57506000610d47565b8282028284828161466b57fe5b0414611c215760405162461bcd60e51b815260040161067e9061594e565b60008082116146aa5760405162461bcd60e51b815260040161067e906158be565b60008284816146b557fe5b04949350505050565b6000806146e4766578743a41676772656761746f7244656274526174696f60481b612d65565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561471c57600080fd5b505afa158015614730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506147549190810190614d82565b5050509150508060001461477757614772838263ffffffff612dc216565b611c21565b50600092915050565b60008261478f57506001610d47565b8161479d5750600019610d47565b818311156147bc576147b5838363ffffffff61397216565b9050610d47565b611c21828463ffffffff61397216565b60006147d66143b9565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f7072696365446576696174696f6e5468726573686f6c64466163746f720000006040518363ffffffff1660e01b8152600401612e35929190615789565b60006109e86b53797374656d53746174757360a01b612d65565b6000611c2183836b033b2e3c9fd0803ce80000005b600080600a830461487a868663ffffffff61464f16565b8161488157fe5b0490506005600a826143a3565b815481835581811115610da057600083815260209020610da09181019083016109eb91905b80821115613e2657600081556001016148b3565b8035610d4781615b18565b8051610d4781615b18565b60008083601f8401126148ef57600080fd5b50813567ffffffffffffffff81111561490757600080fd5b602083019150836020820283011115613d8157600080fd5b600082601f83011261493057600080fd5b815161494361493e82615a39565b615a12565b9150818183526020840193506020810190508385602084028201111561496857600080fd5b60005b83811015614994578161497e88826149bf565b845250602092830192919091019060010161496b565b5050505092915050565b8035610d4781615b2c565b8051610d4781615b2c565b8035610d4781615b35565b8051610d4781615b35565b8035610d4781615b3e565b8051610d4781615b3e565b8035610d4781615b47565b8051610d4781615b47565b8051610d4781615b50565b600060208284031215614a1357600080fd5b600061452b84846148c7565b600060208284031215614a3157600080fd5b600061452b84846148d2565b60008060408385031215614a5057600080fd5b6000614a5c85856148c7565b9250506020614a6d858286016148c7565b9150509250929050565b600080600060608486031215614a8c57600080fd5b6000614a9886866148c7565b9350506020614aa9868287016148c7565b9250506040614aba868287016149b4565b9150509250925092565b60008060408385031215614ad757600080fd5b6000614ae385856148c7565b9250506020614a6d8582860161499e565b60008060408385031215614b0757600080fd5b6000614b1385856148c7565b9250506020614a6d858286016149b4565b60008060208385031215614b3757600080fd5b823567ffffffffffffffff811115614b4e57600080fd5b614b5a858286016148dd565b92509250509250929050565b60008060408385031215614b7957600080fd5b825167ffffffffffffffff811115614b9057600080fd5b614b9c8582860161491f565b9250506020614a6d858286016149a9565b600060208284031215614bbf57600080fd5b600061452b84846149a9565b600060208284031215614bdd57600080fd5b600061452b84846149b4565b600060208284031215614bfb57600080fd5b600061452b84846149bf565b600080600060608486031215614c1c57600080fd5b6000614a9886866149b4565b60008060408385031215614c3b57600080fd5b6000614ae385856149b4565b600060208284031215614c5957600080fd5b600061452b84846149ca565b600060208284031215614c7757600080fd5b600061452b84846149d5565b600060208284031215614c9557600080fd5b600061452b84846149e0565b600060208284031215614cb357600080fd5b600061452b84846149eb565b60008060408385031215614cd257600080fd5b6000614b9c85856149bf565b60008060008060808587031215614cf457600080fd5b6000614d0087876149bf565b9450506020614d11878288016149bf565b9350506040614d22878288016149a9565b9250506060614d33878288016149a9565b91505092959194509250565b600080600060608486031215614d5457600080fd5b6000614d6086866149bf565b9350506020614d71868287016149bf565b9250506040614aba868287016149bf565b600080600080600060a08688031215614d9a57600080fd5b6000614da688886149f6565b9550506020614db7888289016149bf565b9450506040614dc8888289016149bf565b9350506060614dd9888289016149bf565b9250506080614dea888289016149f6565b9150509295509295909350565b6000614e038383614f6e565b505060200190565b6000614e038383614f88565b614e2081615a72565b82525050565b614e20614e3282615a72565b615af7565b6000614e438385615a64565b93506001600160fb1b03831115614e5957600080fd5b602083029250614e6a838584615abf565b50500190565b6000614e7b82615a60565b614e858185615a64565b9350614e9083615a5a565b8060005b83811015614ebe578151614ea88882614df7565b9750614eb383615a5a565b925050600101614e94565b509495945050505050565b6000614ed482615a60565b614ede8185615a64565b9350614ee983615a5a565b8060005b83811015614ebe578151614f018882614e0b565b9750614f0c83615a5a565b925050600101614eed565b6000614f2282615a60565b614f2c8185615a64565b9350614f3783615a5a565b8060005b83811015614ebe578151614f4f8882614df7565b9750614f5a83615a5a565b925050600101614f3b565b614e2081615a7d565b614e20816109eb565b614e20614f83826109eb565b6109eb565b614e2081615a82565b614e2081615ab4565b6000614fa582615a60565b614faf8185615a64565b9350614fbf818560208601615acb565b614fc881615b08565b9093019392505050565b6000614fdf603583615a64565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b6000615036601d83615a64565b7f4e6f7420617070726f76656420746f20616374206f6e20626568616c66000000815260200192915050565b600061506f601b83615a64565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006150a8603f83615a64565b7f4973737565723a204f6e6c79207468652053796e746852656465656d6572206381527f6f6e74726163742063616e20706572666f726d207468697320616374696f6e00602082015260400192915050565b6000615107601283615a64565b714e6f206465627420746f20666f726769766560701b815260200192915050565b6000615135601083615a64565b6f416d6f756e7420746f6f206c6172676560801b815260200192915050565b6000615161601e83615a64565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b600061519a601a83615a64565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b60006151d3601183615a6d565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b6000615200603b83615a64565b7f4973737565723a204f6e6c79207468652073796e74686574697820636f6e747281527f6163742063616e20706572666f726d207468697320616374696f6e0000000000602082015260400192915050565b600061525f601083615a64565b6f135d5cdd08189948199959481c1bdbdb60821b815260200192915050565b600061528b601e83615a64565b7f412073796e7468206f7220534e58207261746520697320696e76616c69640000815260200192915050565b60006152c4601483615a64565b7314de5b9d1a08191bd95cc81b9bdd08195e1a5cdd60621b815260200192915050565b60006152f4602a83615a64565b7f43616e6e6f742072656d6f76652073796e746820746f2072656465656d20776981526974686f7574207261746560b01b602082015260400192915050565b6000615340601883615a64565b7f4e6f74206f70656e20666f72206c69717569646174696f6e0000000000000000815260200192915050565b6000615379602f83615a64565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b631cd554d160e21b9052565b60006153d6601c83615a64565b7f53796e7468206164647265737320616c72656164792065786973747300000000815260200192915050565b600061540f602183615a64565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000615452601383615a64565b72086c2dcdcdee840e4cadadeecca40e6f2dce8d606b1b815260200192915050565b6000615481601d83615a64565b7f4973737565723a2063616e6e6f7420697373756520302073796e746873000000815260200192915050565b60006154ba601983615a6d565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b60006154f3603483615a64565b7f4973737565723a204f6e6c792074727573746564206d696e746572732063616e815273103832b93337b936903a3434b99030b1ba34b7b760611b602082015260400192915050565b6000615549600c83615a64565b6b53796e74682065786973747360a01b815260200192915050565b6000615571601b83615a64565b7f4973737565723a2073796e746820646f65736e27742065786973740000000000815260200192915050565b60006155aa601e83615a64565b7f4d696e696d756d207374616b652074696d65206e6f7420726561636865640000815260200192915050565b60006155e3602883615a64565b7f53616665436173743a2076616c756520646f65736e27742066697420696e2061815267371034b73a191a9b60c11b602082015260400192915050565b614e2081615a8d565b60006156358285614f77565b6020820191506156458284614e26565b5060140192915050565b600061565a826151c6565b91506156668284614f77565b50602001919050565b600061565a826154ad565b60208101610d478284614e17565b604081016156968285614e17565b611c216020830184614e17565b604081016156b18285614e17565b611c216020830184614f65565b604081016156cc8285614e17565b611c216020830184614f6e565b608081016156e78287614e17565b6156f46020830186614f6e565b6157016040830185614f6e565b61570e6060830184614f6e565b95945050505050565b60408082528101615729818587614e37565b9050818103602083015261570e8184614f17565b60208082528101611c218184614e70565b60208082528101611c218184614ec9565b60208101610d478284614f65565b60208101610d478284614f6e565b604081016156968285614f6e565b604081016156cc8285614f6e565b606081016157a58286614f6e565b6157b26020830185614f6e565b61452b6040830184614f6e565b604081016157cd8285614f6e565b611c216020830184614f91565b604081016157e88285614f6e565b818103602083015261452b8184614f9a565b606081016158088285614f6e565b6158156020830184614f6e565b611c21604083016153bd565b60208101610d478284614f88565b604081016156cc8285614f88565b60208082528101611c218184614f9a565b60208082528101610d4781614fd2565b60208082528101610d4781615029565b60208082528101610d4781615062565b60208082528101610d478161509b565b60208082528101610d47816150fa565b60208082528101610d4781615128565b60208082528101610d4781615154565b60208082528101610d478161518d565b60208082528101610d47816151f3565b60208082528101610d4781615252565b60208082528101610d478161527e565b60208082528101610d47816152b7565b60208082528101610d47816152e7565b60208082528101610d4781615333565b60208082528101610d478161536c565b60208082528101610d47816153c9565b60208082528101610d4781615402565b60208082528101610d4781615445565b60208082528101610d4781615474565b60208082528101610d47816154e6565b60208082528101610d478161553c565b60208082528101610d4781615564565b60208082528101610d478161559d565b60208082528101610d47816155d6565b60208101610d478284615620565b604081016156b18285614f6e565b606081016159f88286614f6e565b615a056020830185614f6e565b61452b6040830184614f65565b60405181810167ffffffffffffffff81118282101715615a3157600080fd5b604052919050565b600067ffffffffffffffff821115615a5057600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b919050565b6000610d4782615a99565b151590565b6000610d4782615a72565b6001600160801b031690565b6001600160a01b031690565b69ffffffffffffffffffff1690565b6000610d47826109eb565b82818337506000910152565b60005b83811015615ae6578181015183820152602001615ace565b838111156143605750506000910152565b6000610d47826000610d4782615b12565b601f01601f191690565b60601b90565b615b2181615a72565b8114610ea857600080fd5b615b2181615a7d565b615b21816109eb565b615b2181615a82565b615b2181615a8d565b615b2181615aa556fea365627a7a723158203c078130d94a2603aff4f5dc68420bee29b14e014577e62bdd00a58f9314915a6c6578706572696d656e74616cf564736f6c6343000510004000000000000000000000000073570075092502472e4b61a7058df1a4a1db12f2000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2

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

00000000000000000000000073570075092502472e4b61a7058df1a4a1db12f2000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2

-----Decoded View---------------
Arg [0] : _owner (address): 0x73570075092502472e4b61a7058df1a4a1db12f2
Arg [1] : _resolver (address): 0x242a3df52c375bee81b1c668741d7c63af68fdd2

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000073570075092502472e4b61a7058df1a4a1db12f2
Arg [1] : 000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2


Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

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.