Contract 0x2709b3568a79D7E00d6729E96b84a1996CDB89ef

Contract Overview

Balance:
0 Ether
Txn Hash Method
Block
From
To
Value
0xb4882915cf2d87710b1e02c8752eb64575e6e7033d1d2ef00db70d3488917bffAccept Ownership243386522021-04-19 21:39:1228 days 23 hrs ago0x73570075092502472e4b61a7058df1a4a1db12f2 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0000217861
0x204b8d9bf1b7330a77d23df67dbac230ce83ba7737a6495bec3cee1d4d1858f9Nominate New Own...243377262021-04-19 20:36:3629 days 33 mins ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0000444591
0x9132c0121d22b0937caab80d871c1b1e8e32e3f3841cad96d5426b2a2408f57bIssue Synths242403602021-04-13 11:54:2835 days 9 hrs ago0x0713a0c92019d867ff978c83074d4475c2a1493b IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.000115865
0x2824a1f018094de67b9ed9364230c7f04257f8471b032eaf3d7a90fce808aeb9Add Synths240317772021-03-23 19:50:5256 days 1 hr ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0001236671
0x06b2ffdf97d988b588a17c43efca6ef5fd9d9470da7959259005699a8f3931f3Issue Synths239236992021-03-15 3:44:4864 days 17 hrs ago0x0713a0c92019d867ff978c83074d4475c2a1493b IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0002314810
0x81648fb52ce4306deab0bba4a144d65f29fc9fa81cdeb862324609bad9790affIssue Synths239236292021-03-15 3:38:2464 days 17 hrs ago0x0713a0c92019d867ff978c83074d4475c2a1493b IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0002314810
0xd84738f66cc0ceeab2877e3203412334714050ca0ec45f78d770b21f915c3a67Issue Synths239231612021-03-15 2:56:1664 days 18 hrs ago0x0713a0c92019d867ff978c83074d4475c2a1493b IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0002314810
0x8b0ce070553e05a7b4d4a42df05e8301255accb6f0bd09cb6b5c7192c102bc01Add Synths234116352021-02-11 0:03:4096 days 21 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0001236671
0xe7b80114f76c183d74929bc8ea007a751a1f0f3779500517d75c9c5b554c51a5Remove Synth232986592021-02-03 23:53:16103 days 21 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0003731583
0xdeb9ab8da57086bafbd66cbca7c56e0de9daee0b37b140e55c2460ce64886d88Remove Synth232982632021-02-03 23:17:48103 days 21 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0004183833
0x30968cb20060df6a68799305afe6f895d017690071a720f7084e420da6059dfcRemove Synth232982512021-02-03 23:16:44103 days 21 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.000453
0x781b53ec066c15b60ce282440cdc76abc03897ac2a7fbfd649fc3d1b14a375f0Remove Synth232981512021-02-03 23:07:48103 days 22 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.000453
0x6179920c584dc5768647036bb556b484a0de981aacb1a2779c4924c64bf9e9f7Add Synth232980212021-02-03 22:56:12103 days 22 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0003030873
0x60e8e3a89bee0361b25e5d944d4774e3c1a7c38b994d78c069f6caef9c84d97dRemove Synth232980162021-02-03 22:55:44103 days 22 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.000325923
0xaacbf13c66164759117063255c22934c5c8f7f2066e3408cf9e45385a9a8e1c0Add Synths229977272021-01-13 15:50:32125 days 5 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0014593042
0x457dee1c30169dda6ed21cdf33302f52ef50788b3fbd1dc0b208c085f53889b6Add Synths229977262021-01-13 15:50:24125 days 5 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0021569722
0x6fb474bc663b505d0fb7d149d9dea7d194572d041d804c48ecb4052136d09f31Add Synths229977252021-01-13 15:50:20125 days 5 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether0.0022310062
0xf6d9a8318ad01a58da783efeb23ffd34b3a0934ab76ba1c76e3081d8a7fb0baa0x60806040229976922021-01-13 15:46:40125 days 5 hrs ago0xb64ff7a4a33acdf48d97dab0d764afd0f6176882 IN  Contract Creation0 Ether0.0080492862
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xdb28144cc8eee2b4ed6a943efd5e7c750d856aa1c1949d23eabe1a997a99c769248090072021-05-13 6:18:325 days 14 hrs ago 0xdcb48e969e69df65f72f77b2aae145509733e5c0 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xdb28144cc8eee2b4ed6a943efd5e7c750d856aa1c1949d23eabe1a997a99c769248090072021-05-13 6:18:325 days 14 hrs ago 0xdcb48e969e69df65f72f77b2aae145509733e5c0 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x072056ef09b9878b025be761b25c0997eedaf9d5d4d1c5e1bfea7186c722ef55248064152021-05-13 2:02:205 days 19 hrs ago 0xdcb48e969e69df65f72f77b2aae145509733e5c0 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x072056ef09b9878b025be761b25c0997eedaf9d5d4d1c5e1bfea7186c722ef55248064152021-05-13 2:02:205 days 19 hrs ago 0xa0354c17832e34daf2aeae968af3dc558d5c6dc6 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x072056ef09b9878b025be761b25c0997eedaf9d5d4d1c5e1bfea7186c722ef55248064152021-05-13 2:02:205 days 19 hrs ago 0xf1d0ee19af243bcbc140a2259290b490e4df92a9 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x072056ef09b9878b025be761b25c0997eedaf9d5d4d1c5e1bfea7186c722ef55248064152021-05-13 2:02:205 days 19 hrs ago 0xf1d0ee19af243bcbc140a2259290b490e4df92a9 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x072056ef09b9878b025be761b25c0997eedaf9d5d4d1c5e1bfea7186c722ef55248064152021-05-13 2:02:205 days 19 hrs ago 0xf1d0ee19af243bcbc140a2259290b490e4df92a9 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x072056ef09b9878b025be761b25c0997eedaf9d5d4d1c5e1bfea7186c722ef55248064152021-05-13 2:02:205 days 19 hrs ago 0xf1d0ee19af243bcbc140a2259290b490e4df92a9 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x3c9511b6aacae18707e9eeabbaca6793799f00f02cd17c49592ba4e9fcef6ee1248063692021-05-13 1:57:445 days 19 hrs ago 0xdcb48e969e69df65f72f77b2aae145509733e5c0 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x3c9511b6aacae18707e9eeabbaca6793799f00f02cd17c49592ba4e9fcef6ee1248063692021-05-13 1:57:445 days 19 hrs ago 0xa0354c17832e34daf2aeae968af3dc558d5c6dc6 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x3c9511b6aacae18707e9eeabbaca6793799f00f02cd17c49592ba4e9fcef6ee1248063692021-05-13 1:57:445 days 19 hrs ago 0xf1d0ee19af243bcbc140a2259290b490e4df92a9 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x3c9511b6aacae18707e9eeabbaca6793799f00f02cd17c49592ba4e9fcef6ee1248063692021-05-13 1:57:445 days 19 hrs ago 0xf1d0ee19af243bcbc140a2259290b490e4df92a9 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x3c9511b6aacae18707e9eeabbaca6793799f00f02cd17c49592ba4e9fcef6ee1248063692021-05-13 1:57:445 days 19 hrs ago 0xf1d0ee19af243bcbc140a2259290b490e4df92a9 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x2b66d93a64fe10eb5a820a61e38130e78363148d25251a737edbe929ea6780c2248040602021-05-12 22:08:325 days 23 hrs ago 0xdcb48e969e69df65f72f77b2aae145509733e5c0 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0x2b66d93a64fe10eb5a820a61e38130e78363148d25251a737edbe929ea6780c2248040602021-05-12 22:08:325 days 23 hrs ago 0xdcb48e969e69df65f72f77b2aae145509733e5c0 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
0xd825781ff60114b6b44789f0f99893951e2bc57c2ab624fa747916bf03265485248017742021-05-12 18:22:206 days 2 hrs ago 0x07acc2b253218535c21a3e57bcb81eb13345a34a 0x2709b3568a79d7e00d6729e96b84a1996cdb89ef0 Ether
[ Download CSV Export 
Loading

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 2021-01-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: 
*	- SafeDecimalMath
*	- SafeMath
*
* MIT License
* ===========
*
* Copyright (c) 2021 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 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 excludeEtherCollateral) 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 liquidateDelinquentAccount(
        address account,
        uint susdAmount,
        address liquidator
    ) external returns (uint totalRedeemed, uint amountToLiquidate);
}


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


// solhint-disable payable-fallback

// https://docs.synthetix.io/contracts/source/contracts/readproxy
contract ReadProxy is Owned {
    address public target;

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

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

    function() external {
        // The basics of a proxy read call
        // Note that msg.sender in the underlying will always be the address of this contract.
        assembly {
            calldatacopy(0, 0, calldatasize)

            // Use of staticcall - this will revert if the underlying function mutates state
            let result := staticcall(gas, sload(target_slot), 0, calldatasize, 0, 0)
            returndatacopy(0, 0, returndatasize)

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

    event TargetUpdated(address newTarget);
}


// Inheritance


// 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 {
    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_PENALTY = "liquidationPenalty";
    bytes32 internal constant SETTING_RATE_STALE_PERIOD = "rateStalePeriod";
    bytes32 internal constant SETTING_EXCHANGE_FEE_RATE = "exchangeFeeRate";
    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 CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage";

    enum CrossDomainMessageGasLimits {Deposit, Escrow, Reward, Withdrawal}

    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 {
            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 getLiquidationPenalty() internal view returns (uint) {
        return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_PENALTY);
    }

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

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

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


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


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 totalIssuedSynthsExcludeEtherCollateral(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 originator,
        bytes32 trackingCode
    ) external returns (uint amountReceived);

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

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

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

    // Restricted: used internally to Synthetix
    function appendAccountIssuanceRecord(
        address account,
        uint lockedAmount,
        uint debtEntryIndex
    ) external;

    function recordFeePaid(uint sUSDAmount) external;

    function setRewardsToDistribute(uint amount) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/isynthetixstate
interface ISynthetixState {
    // Views
    function debtLedger(uint index) external view returns (uint);

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

    function debtLedgerLength() external view returns (uint);

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

    function lastDebtLedgerEntry() external view returns (uint);

    // Mutative functions
    function incrementTotalIssuerCount() external;

    function decrementTotalIssuerCount() external;

    function setCurrentIssuanceData(address account, uint initialDebtOwnership) external;

    function appendDebtLedgerValue(uint value) external;

    function clearIssuanceData(address account) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/iexchanger
interface IExchanger {
    // 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 exchangeFeeRate);

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

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

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

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

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

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

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

    function setLastExchangeRateForSynth(bytes32 currencyKey, uint rate) external;

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

    struct InversePricing {
        uint entryPoint;
        uint upperLimit;
        uint lowerLimit;
        bool frozenAtUpperLimit;
        bool frozenAtLowerLimit;
    }

    // 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 canFreezeRate(bytes32 currencyKey) external view returns (bool);

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

    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 effectiveValueAtRound(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        uint roundIdForSrc,
        uint roundIdForDest
    ) external view returns (uint value);

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

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

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

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

    function oracle() external view returns (address);

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

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

    // Mutative functions
    function freezeRate(bytes32 currencyKey) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/iethercollateral
interface IEtherCollateral {
    // Views
    function totalIssuedSynths() external view returns (uint256);

    function totalLoansCreated() external view returns (uint256);

    function totalOpenLoanCount() external view returns (uint256);

    // Mutative functions
    function openLoan() external payable returns (uint256 loanID);

    function closeLoan(uint256 loanID) external;

    function liquidateUnclosedLoan(address _loanCreatorsAddress, uint256 _loanID) external;
}


// https://docs.synthetix.io/contracts/source/interfaces/iethercollateralsusd
interface IEtherCollateralsUSD {
    // Views
    function totalIssuedSynths() external view returns (uint256);

    function totalLoansCreated() external view returns (uint256);

    function totalOpenLoanCount() external view returns (uint256);

    // Mutative functions
    function openLoan(uint256 _loanAmount) external payable returns (uint256 loanID);

    function closeLoan(uint256 loanID) external;

    function liquidateUnclosedLoan(address _loanCreatorsAddress, uint256 _loanID) external;

    function depositCollateral(address account, uint256 loanID) external payable;

    function withdrawCollateral(uint256 loanID, uint256 withdrawAmount) external;

    function repayLoan(
        address _loanCreatorsAddress,
        uint256 _loanID,
        uint256 _repayAmount
    ) external;
}


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


// https://docs.synthetix.io/contracts/source/interfaces/iliquidations
interface ILiquidations {
    // Views
    function isOpenForLiquidation(address account) external view returns (bool);

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

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

    function liquidationDelay() external view returns (uint);

    function liquidationRatio() external view returns (uint);

    function liquidationPenalty() external view returns (uint);

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

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

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

    function checkAndRemoveAccountInLiquidation(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[2][] calldata requiredSynthAndInverseNamesInResolver, bytes32[] calldata synthKeys)
        external;

    function removeShortableSynths(bytes32[] calldata synths) external;

    // State mutative
    function updateBorrowRates(uint rate) external;

    function updateShortRates(bytes32 currency, uint rate) external;

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


// https://docs.synthetix.io/contracts/source/interfaces/idebtcache
interface IDebtCache {
    // Views

    function cachedDebt() external view returns (uint);

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

    function cacheTimestamp() external view returns (uint);

    function cacheInvalid() external view returns (bool);

    function cacheStale() external view returns (bool);

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

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

    function currentDebt() external view returns (uint debt, bool anyRateIsInvalid);

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

    // Mutative functions

    function takeDebtSnapshot() external;

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


// Inheritance


// Libraries


// Internal references


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


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

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

    function updateDebtCacheValidity(bool currentlyInvalid) external;

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


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

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

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

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

    // Flexible storage names

    bytes32 public constant CONTRACT_NAME = "Issuer";
    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_SYNTHETIXSTATE = "SynthetixState";
    bytes32 private constant CONTRACT_FEEPOOL = "FeePool";
    bytes32 private constant CONTRACT_DELEGATEAPPROVALS = "DelegateApprovals";
    bytes32 private constant CONTRACT_ETHERCOLLATERAL = "EtherCollateral";
    bytes32 private constant CONTRACT_ETHERCOLLATERAL_SUSD = "EtherCollateralsUSD";
    bytes32 private constant CONTRACT_COLLATERALMANAGER = "CollateralManager";
    bytes32 private constant CONTRACT_REWARDESCROW_V2 = "RewardEscrowV2";
    bytes32 private constant CONTRACT_SYNTHETIXESCROW = "SynthetixEscrow";
    bytes32 private constant CONTRACT_LIQUIDATIONS = "Liquidations";
    bytes32 private constant CONTRACT_DEBTCACHE = "DebtCache";

    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[](13);
        newAddresses[0] = CONTRACT_SYNTHETIX;
        newAddresses[1] = CONTRACT_EXCHANGER;
        newAddresses[2] = CONTRACT_EXRATES;
        newAddresses[3] = CONTRACT_SYNTHETIXSTATE;
        newAddresses[4] = CONTRACT_FEEPOOL;
        newAddresses[5] = CONTRACT_DELEGATEAPPROVALS;
        newAddresses[6] = CONTRACT_ETHERCOLLATERAL;
        newAddresses[7] = CONTRACT_ETHERCOLLATERAL_SUSD;
        newAddresses[8] = CONTRACT_REWARDESCROW_V2;
        newAddresses[9] = CONTRACT_SYNTHETIXESCROW;
        newAddresses[10] = CONTRACT_LIQUIDATIONS;
        newAddresses[11] = CONTRACT_DEBTCACHE;
        newAddresses[12] = CONTRACT_COLLATERALMANAGER;
        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 synthetixState() internal view returns (ISynthetixState) {
        return ISynthetixState(requireAndGetAddress(CONTRACT_SYNTHETIXSTATE));
    }

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

    function liquidations() internal view returns (ILiquidations) {
        return ILiquidations(requireAndGetAddress(CONTRACT_LIQUIDATIONS));
    }

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

    function etherCollateral() internal view returns (IEtherCollateral) {
        return IEtherCollateral(requireAndGetAddress(CONTRACT_ETHERCOLLATERAL));
    }

    function etherCollateralsUSD() internal view returns (IEtherCollateralsUSD) {
        return IEtherCollateralsUSD(requireAndGetAddress(CONTRACT_ETHERCOLLATERAL_SUSD));
    }

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

    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 issuanceRatio() external view returns (uint) {
        return getIssuanceRatio();
    }

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

    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) {
            // Get the sUSD equivalent amount of all the MC issued synths.
            (uint nonSnxDebt, bool invalid) = collateralManager().totalLong();
            debt = debt.add(nonSnxDebt);
            anyRateIsInvalid = anyRateIsInvalid || invalid;

            // Now add the ether collateral stuff as we are still supporting it.
            debt = debt.add(etherCollateralsUSD().totalIssuedSynths());

            // Add ether collateral sETH
            (uint ethRate, bool ethRateInvalid) = exRates.rateAndInvalid(sETH);
            uint ethIssuedDebt = etherCollateral().totalIssuedSynths().multiplyDecimalRound(ethRate);
            debt = debt.add(ethIssuedDebt);
            anyRateIsInvalid = anyRateIsInvalid || ethRateInvalid;
        }

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

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

    function _debtBalanceOfAndTotalDebt(address _issuer, bytes32 currencyKey)
        internal
        view
        returns (
            uint debtBalance,
            uint totalSystemValue,
            bool anyRateIsInvalid
        )
    {
        ISynthetixState state = synthetixState();

        // What was their initial debt ownership?
        (uint initialDebtOwnership, uint debtEntryIndex) = state.issuanceData(_issuer);

        // What's the total value of the system excluding ETH backed synths in their requested currency?
        (totalSystemValue, anyRateIsInvalid) = _totalIssuedSynths(currencyKey, true);

        // If it's zero, they haven't issued, and they have no debt.
        // Note: it's more gas intensive to put this check here rather than before _totalIssuedSynths
        // if they have 0 SNX, but it's a necessary trade-off
        if (initialDebtOwnership == 0) return (0, totalSystemValue, anyRateIsInvalid);

        // Figure out the global debt percentage delta from when they entered the system.
        // This is a high precision integer of 27 (1e27) decimals.
        uint currentDebtOwnership = state
            .lastDebtLedgerEntry()
            .divideDecimalRoundPrecise(state.debtLedger(debtEntryIndex))
            .multiplyDecimalRoundPrecise(initialDebtOwnership);

        // Their debt balance is their portion of the total system value.
        uint highPrecisionBalance = totalSystemValue.decimalToPreciseDecimal().multiplyDecimalRoundPrecise(
            currentDebtOwnership
        );

        // Convert back into 18 decimals (1e18)
        debtBalance = highPrecisionBalance.preciseDecimalToDecimal();
    }

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

        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 excludeEtherCollateral) external view returns (uint totalIssued) {
        (totalIssued, ) = _totalIssuedSynths(currencyKey, excludeEtherCollateral);
    }

    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) {
        ISynthetixState state = synthetixState();

        // What was their initial debt ownership?
        (uint initialDebtOwnership, ) = state.issuanceData(_issuer);

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

        (debtBalance, , ) = _debtBalanceOfAndTotalDebt(_issuer, 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(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(IERC20(synthToRemove).totalSupply() == 0, "Synth supply exists");
        require(currencyKey != sUSD, "Cannot remove synth");

        // 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 issueSynths(address from, uint amount) external onlySynthetix {
        _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 liquidateDelinquentAccount(
        address account,
        uint susdAmount,
        address liquidator
    ) external onlySynthetix returns (uint totalRedeemed, uint amountToLiquidate) {
        // Ensure waitingPeriod and sUSD balance is settled as burning impacts the size of debt pool
        require(!exchanger().hasWaitingPeriodOrSettlementOwing(liquidator, sUSD), "sUSD needs to be settled");

        // Check account is liquidation open
        require(liquidations().isOpenForLiquidation(account), "Account not open for liquidation");

        // require liquidator has enough sUSD
        require(IERC20(address(synths[sUSD])).balanceOf(liquidator) >= susdAmount, "Not enough sUSD");

        uint liquidationPenalty = liquidations().liquidationPenalty();

        // What is their debt in sUSD?
        (uint debtBalance, uint totalDebtIssued, bool anyRateIsInvalid) = _debtBalanceOfAndTotalDebt(account, sUSD);
        (uint snxRate, bool snxRateInvalid) = exchangeRates().rateAndInvalid(SNX);
        _requireRatesNotInvalid(anyRateIsInvalid || snxRateInvalid);

        uint collateralForAccount = _collateral(account);
        uint amountToFixRatio = liquidations().calculateAmountToFixCollateral(
            debtBalance,
            _snxToUSD(collateralForAccount, snxRate)
        );

        // Cap amount to liquidate to repair collateral ratio based on issuance ratio
        amountToLiquidate = amountToFixRatio < susdAmount ? amountToFixRatio : susdAmount;

        // what's the equivalent amount of snx for the amountToLiquidate?
        uint snxRedeemed = _usdToSnx(amountToLiquidate, snxRate);

        // Add penalty
        totalRedeemed = snxRedeemed.multiplyDecimal(SafeDecimalMath.unit().add(liquidationPenalty));

        // if total SNX to redeem is greater than account's collateral
        // account is under collateralised, liquidate all collateral and reduce sUSD to burn
        if (totalRedeemed > collateralForAccount) {
            // set totalRedeemed to all transferable collateral
            totalRedeemed = collateralForAccount;

            // whats the equivalent sUSD to burn for all collateral less penalty
            amountToLiquidate = _snxToUSD(
                collateralForAccount.divideDecimal(SafeDecimalMath.unit().add(liquidationPenalty)),
                snxRate
            );
        }

        // burn sUSD from messageSender (liquidator) and reduce account's debt
        _burnSynths(account, liquidator, amountToLiquidate, debtBalance, totalDebtIssued);

        // Remove liquidation flag if amount liquidated fixes ratio
        if (amountToLiquidate == amountToFixRatio) {
            // Remove liquidation
            liquidations().removeAccountInLiquidation(account);
        }
    }

    /* ========== 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 {
        (uint maxIssuable, uint existingDebt, uint totalSystemDebt, 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, existingDebt, totalSystemDebt);

        // record issue timestamp
        _setLastIssueEvent(from);

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

        // Account for the issued debt in the cache
        debtCache().updateCachedSynthDebtWithRate(sUSD, SafeDecimalMath.unit());

        // Store their locked SNX amount to determine their fee % for the period
        _appendAccountIssuanceRecord(from);
    }

    function _burnSynths(
        address debtAccount,
        address burnAccount,
        uint amount,
        uint existingDebt,
        uint totalDebtIssued
    ) internal returns (uint amountBurnt) {
        // 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, totalDebtIssued);

        // 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().updateCachedSynthDebtWithRate(sUSD, SafeDecimalMath.unit());

        // Store their debtRatio against a fee period to determine their fee/rewards % for the period
        _appendAccountIssuanceRecord(debtAccount);
    }

    // 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 {
        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, uint totalSystemValue, bool anyRateIsInvalid) = _debtBalanceOfAndTotalDebt(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, totalSystemValue);

        // Check and remove liquidation if existingDebt after burning is <= maxIssuableSynths
        // Issuance ratio is fixed so should remove any liquidations
        if (existingDebt.sub(amountBurnt) <= maxIssuableSynthsForAccount) {
            liquidations().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 _appendAccountIssuanceRecord(address from) internal {
        uint initialDebtOwnership;
        uint debtEntryIndex;
        (initialDebtOwnership, debtEntryIndex) = synthetixState().issuanceData(from);
        feePool().appendAccountIssuanceRecord(from, initialDebtOwnership, debtEntryIndex);
    }

    function _addToDebtRegister(
        address from,
        uint amount,
        uint existingDebt,
        uint totalDebtIssued
    ) internal {
        ISynthetixState state = synthetixState();

        // What will the new total be including the new value?
        uint newTotalDebtIssued = amount.add(totalDebtIssued);

        // What is their percentage (as a high precision int) of the total debt?
        uint debtPercentage = amount.divideDecimalRoundPrecise(newTotalDebtIssued);

        // And what effect does this percentage change have on the global debt holding of other issuers?
        // The delta specifically needs to not take into account any existing debt as it's already
        // accounted for in the delta from when they issued previously.
        // The delta is a high precision integer.
        uint delta = SafeDecimalMath.preciseUnit().sub(debtPercentage);

        // And what does their debt ownership look like including this previous stake?
        if (existingDebt > 0) {
            debtPercentage = amount.add(existingDebt).divideDecimalRoundPrecise(newTotalDebtIssued);
        } else {
            // If they have no debt, they're a new issuer; record this.
            state.incrementTotalIssuerCount();
        }

        // Save the debt entry parameters
        state.setCurrentIssuanceData(from, debtPercentage);

        // And if we're the first, push 1 as there was no effect to any other holders, otherwise push
        // the change for the rest of the debt holders. The debt ledger holds high precision integers.
        if (state.debtLedgerLength() > 0) {
            state.appendDebtLedgerValue(state.lastDebtLedgerEntry().multiplyDecimalRoundPrecise(delta));
        } else {
            state.appendDebtLedgerValue(SafeDecimalMath.preciseUnit());
        }
    }

    function _removeFromDebtRegister(
        address from,
        uint debtToRemove,
        uint existingDebt,
        uint totalDebtIssued
    ) internal {
        ISynthetixState state = synthetixState();

        // What will the new total after taking out the withdrawn amount
        uint newTotalDebtIssued = totalDebtIssued.sub(debtToRemove);

        uint delta = 0;

        // What will the debt delta be if there is any debt left?
        // Set delta to 0 if no more debt left in system after user
        if (newTotalDebtIssued > 0) {
            // What is the percentage of the withdrawn debt (as a high precision int) of the total debt after?
            uint debtPercentage = debtToRemove.divideDecimalRoundPrecise(newTotalDebtIssued);

            // And what effect does this percentage change have on the global debt holding of other issuers?
            // The delta specifically needs to not take into account any existing debt as it's already
            // accounted for in the delta from when they issued previously.
            delta = SafeDecimalMath.preciseUnit().add(debtPercentage);
        }

        // Are they exiting the system, or are they just decreasing their debt position?
        if (debtToRemove == existingDebt) {
            state.setCurrentIssuanceData(from, 0);
            state.decrementTotalIssuerCount();
        } else {
            // What percentage of the debt will they be left with?
            uint newDebt = existingDebt.sub(debtToRemove);
            uint newDebtPercentage = newDebt.divideDecimalRoundPrecise(newTotalDebtIssued);

            // Store the debt percentage and debt ledger as high precision integers
            state.setCurrentIssuanceData(from, newDebtPercentage);
        }

        // Update our cumulative ledger. This is also a high precision integer.
        state.appendDebtLedgerValue(state.lastDebtLedgerEntry().multiplyDecimalRoundPrecise(delta));
    }

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

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

    modifier onlySynthetix() {
        _onlySynthetix(); // Use an internal function to save code size.
        _;
    }

    /* ========== 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":"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":"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":"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":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":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":"uint256","name":"susdAmount","type":"uint256"},{"internalType":"address","name":"liquidator","type":"address"}],"name":"liquidateDelinquentAccount","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":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":"excludeEtherCollateral","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"}]

60806040523480156200001157600080fd5b506040516200482a3803806200482a833981810160405260408110156200003757600080fd5b5080516020909101518080836001600160a01b0381166200009f576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a150600280546001600160a01b039092166001600160a01b03199092169190911790555050506146fe806200012c6000396000f3fe608060405234801561001057600080fd5b50600436106102535760003560e01c806372cb051f11610146578063a5fdc5de116100c3578063bff4fdfc11610087578063bff4fdfc1461080c578063c897713214610832578063d37c4d8b14610858578063dbf6334014610884578063dd3d2b2e1461088c578063fd864ccf146108b257610253565b8063a5fdc5de1461073d578063a63c4df414610763578063ae3bbbbb146107b2578063b06e8c65146107d8578063b410a0341461080457610253565b8063849cf5881161010a578063849cf588146106ab578063899ffef4146106d15780638da5cb5b146106d95780639a5154b4146106e1578063a311c7c21461071757610253565b806372cb051f14610651578063741853601461065957806379ba5097146106615780637b1001b714610669578063835e119c1461068e57610253565b806332608039116101d45780634e99bda9116101985780634e99bda91461058657806353a47bb71461058e578063614d08f8146105965780636bed04151461059e5780637168d2c2146105e357610253565b806332608039146103e15780633b6afe40146103fe57806344ec6b62146104bc57806347a9b6db146104f2578063497d704a1461056057610253565b80631627540c1161021b5780631627540c1461034357806316b2213f14610369578063242df9e11461038f5780632af64bd3146103975780632b3f41aa146103b357610253565b8063042e06881461025857806304f3bcec1461028657806305b3c1c9146102aa5780630b887dae146102e25780631137aedf146102ff575b600080fd5b6102846004803603604081101561026e57600080fd5b506001600160a01b0381351690602001356108e0565b005b61028e6108f8565b604080516001600160a01b039092168252519081900360200190f35b6102d0600480360360208110156102c057600080fd5b50356001600160a01b0316610907565b60408051918252519081900360200190f35b610284600480360360208110156102f857600080fd5b503561091b565b6103256004803603602081101561031557600080fd5b50356001600160a01b03166109ff565b60408051938452602084019290925282820152519081900360600190f35b6102846004803603602081101561035957600080fd5b50356001600160a01b0316610a1b565b6102d06004803603602081101561037f57600080fd5b50356001600160a01b0316610a77565b6102d0610a89565b61039f610a99565b604080519115158252519081900360200190f35b610284600480360360408110156103c957600080fd5b506001600160a01b0381358116916020013516610ba3565b61028e600480360360208110156103f757600080fd5b5035610bc2565b61046c6004803603602081101561041457600080fd5b810190602081018135600160201b81111561042e57600080fd5b82018360208201111561044057600080fd5b803590602001918460208302840111600160201b8311171561046157600080fd5b509092509050610bdd565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104a8578181015183820152602001610490565b505050509050019250505060405180910390f35b610284600480360360608110156104d257600080fd5b506001600160a01b03813581169160208101359091169060400135610c8b565b6102846004803603602081101561050857600080fd5b810190602081018135600160201b81111561052257600080fd5b82018360208201111561053457600080fd5b803590602001918460208302840111600160201b8311171561055557600080fd5b509092509050610cae565b6102846004803603602081101561057657600080fd5b50356001600160a01b0316610d5e565b61039f610d76565b61028e610edc565b6102d0610eeb565b6105ca600480360360408110156105b457600080fd5b506001600160a01b038135169060200135610ef8565b6040805192835290151560208301528051918290030190f35b610284600480360360208110156105f957600080fd5b810190602081018135600160201b81111561061357600080fd5b82018360208201111561062557600080fd5b803590602001918460208302840111600160201b8311171561064657600080fd5b509092509050610f5c565b61046c611107565b610284611113565b6102846112d7565b6102d06004803603604081101561067f57600080fd5b50803590602001351515611393565b61028e600480360360208110156106a457600080fd5b503561139f565b610284600480360360208110156106c157600080fd5b50356001600160a01b03166113c6565b61046c611444565b61028e6116ac565b610284600480360360608110156106f757600080fd5b506001600160a01b038135811691602081013590911690604001356116bb565b6102d06004803603602081101561072d57600080fd5b50356001600160a01b03166116d9565b6102d06004803603602081101561075357600080fd5b50356001600160a01b03166116eb565b6107996004803603606081101561077957600080fd5b506001600160a01b038135811691602081013591604090910135166116f6565b6040805192835260208301919091528051918290030190f35b6105ca600480360360208110156107c857600080fd5b50356001600160a01b0316611d33565b610284600480360360408110156107ee57600080fd5b506001600160a01b038135169060200135611d49565b6102d0611d5d565b61039f6004803603602081101561082257600080fd5b50356001600160a01b0316611d67565b6102846004803603602081101561084857600080fd5b50356001600160a01b0316611d72565b6102d06004803603604081101561086e57600080fd5b506001600160a01b038135169060200135611d87565b6102d0611e31565b6102d0600480360360208110156108a257600080fd5b50356001600160a01b0316611e37565b610284600480360360408110156108c857600080fd5b506001600160a01b0381358116916020013516611e42565b6108e8611e61565b6108f482826000611eba565b5050565b6002546001600160a01b031681565b600080610913836120d4565b509392505050565b61092361218f565b600061092d6121d8565b9050806001600160a01b031663d685743a8360006040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b15801561097e57600080fd5b505af1158015610992573d6000803e3d6000fd5b5050604080516304bd11e560e01b81526001600482015290516001600160a01b03851693506304bd11e59250602480830192600092919082900301818387803b1580156109de57600080fd5b505af11580156109f2573d6000803e3d6000fd5b505050506108f4826121ef565b6000806000610a0d846124aa565b509196909550909350915050565b610a2361218f565b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b60066020526000908152604090205481565b6000610a93612512565b90505b90565b60006060610aa5611444565b905060005b8151811015610b9a576000828281518110610ac157fe5b6020908102919091018101516000818152600383526040908190205460025482516321f8a72160e01b81526004810185905292519395506001600160a01b03918216949116926321f8a721926024808201939291829003018186803b158015610b2957600080fd5b505afa158015610b3d573d6000803e3d6000fd5b505050506040513d6020811015610b5357600080fd5b50516001600160a01b0316141580610b8057506000818152600360205260409020546001600160a01b0316155b15610b915760009350505050610a96565b50600101610aaa565b50600191505090565b610bab611e61565b610bb582826125bc565b6108f48260006001612694565b6005602052600090815260409020546001600160a01b031681565b60408051828152602080840282010190915260609082908290828015610c0d578160200160208202803883390190505b50905060005b82811015610c805760056000878784818110610c2b57fe5b90506020020135815260200190815260200160002060009054906101000a90046001600160a01b0316828281518110610c6057fe5b6001600160a01b0390921660209283029190910190910152600101610c13565b509150505b92915050565b610c93611e61565b610c9d838361298e565b610ca983826000611eba565b505050565b610cb661218f565b8060005b81811015610cee57610ce6848483818110610cd157fe5b905060200201356001600160a01b03166129e9565b600101610cba565b50610cf76121d8565b6001600160a01b03166304bd11e560016040518263ffffffff1660e01b81526004018082151515158152602001915050600060405180830381600087803b158015610d4157600080fd5b505af1158015610d55573d6000803e3d6000fd5b50505050505050565b610d66611e61565b610d738160006001612694565b50565b6000610d80612bc6565b6001600160a01b031663c8e5bbd5610d986001612be1565b6040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019060200280838360005b83811015610de7578181015183820152602001610dcf565b505050509050019250505060006040518083038186803b158015610e0a57600080fd5b505afa158015610e1e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015610e4757600080fd5b8101908080516040519392919084600160201b821115610e6657600080fd5b908301906020820185811115610e7b57600080fd5b82518660208202830111600160201b82111715610e9757600080fd5b82525081516020918201928201910280838360005b83811015610ec4578181015183820152602001610eac565b50505050919091016040525060200151949350505050565b6001546001600160a01b031681565b6524b9b9bab2b960d11b81565b6000806000610f0d85620a69cb60eb1b612cbd565b935090915060009050610f2e610f21612ea7565b839063ffffffff612f1d16565b9050848110610f405760009350610f53565b610f50858263ffffffff612f3916565b93505b50509250929050565b610f6461218f565b806000610f6f6121d8565b9050606082604051908082528060200260200182016040528015610f9d578160200160208202803883390190505b509050816001600160a01b03166317b38db48686846040518463ffffffff1660e01b815260040180806020018060200183810383528686828181526020019250602002808284376000838201819052601f909101601f1916909201858103845286518152865160209182019382890193509102908190849084905b83811015611030578181015183820152602001611018565b5050505090500195505050505050600060405180830381600087803b15801561105857600080fd5b505af115801561106c573d6000803e3d6000fd5b5050604080516304bd11e560e01b81526001600482015290516001600160a01b03861693506304bd11e59250602480830192600092919082900301818387803b1580156110b857600080fd5b505af11580156110cc573d6000803e3d6000fd5b506000925050505b838110156110ff576110f78686838181106110eb57fe5b905060200201356121ef565b6001016110d4565b505050505050565b6060610a936000612be1565b606061111d611444565b905060005b81518110156108f457600082828151811061113957fe5b602090810291909101810151600254604080517f5265736f6c766572206d697373696e67207461726765743a2000000000000000818601526039808201859052825180830390910181526059820180845263dacb2d0160e01b9052605d8201858152607d83019384528151609d84015281519597506000966001600160a01b039095169563dacb2d01958995939492939260bd0191908501908083838c5b838110156111ef5781810151838201526020016111d7565b50505050905090810190601f16801561121c5780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b15801561123a57600080fd5b505afa15801561124e573d6000803e3d6000fd5b505050506040513d602081101561126457600080fd5b505160008381526003602090815260409182902080546001600160a01b0319166001600160a01b03851690811790915582518681529182015281519293507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68929081900390910190a15050600101611122565b6001546001600160a01b031633146113205760405162461bcd60e51b815260040180806020018281038252603581526020018061460a6035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60006109138383612f96565b600481815481106113ac57fe5b6000918252602090912001546001600160a01b0316905081565b6113ce61218f565b6113d7816129e9565b6113df6121d8565b6001600160a01b03166304bd11e560016040518263ffffffff1660e01b81526004018082151515158152602001915050600060405180830381600087803b15801561142957600080fd5b505af115801561143d573d6000803e3d6000fd5b5050505050565b60608061144f61333b565b60408051600d8082526101c0820190925291925060609190602082016101a080388339019050509050680a6f2dce8d0cae8d2f60bb1b8160008151811061149257fe5b6020026020010181815250506822bc31b430b733b2b960b91b816001815181106114b857fe5b6020026020010181815250506c45786368616e6765526174657360981b816002815181106114e257fe5b6020026020010181815250506d53796e746865746978537461746560901b8160038151811061150d57fe5b60200260200101818152505066119959541bdbdb60ca1b8160048151811061153157fe5b6020026020010181815250507044656c6567617465417070726f76616c7360781b8160058151811061155f57fe5b6020026020010181815250506e115d1a195c90dbdb1b185d195c985b608a1b8160068151811061158b57fe5b60200260200101818152505072115d1a195c90dbdb1b185d195c985b1cd554d1606a1b816007815181106115bb57fe5b6020026020010181815250506d2932bbb0b93222b9b1b937bbab1960911b816008815181106115e657fe5b6020026020010181815250506e53796e746865746978457363726f7760881b8160098151811061161257fe5b6020026020010181815250506b4c69717569646174696f6e7360a01b81600a8151811061163b57fe5b6020026020010181815250506844656274436163686560b81b81600b8151811061166157fe5b6020026020010181815250507021b7b63630ba32b930b626b0b730b3b2b960791b81600c8151811061168f57fe5b6020026020010181815250506116a5828261338c565b9250505090565b6000546001600160a01b031681565b6116c3611e61565b6116cd83836125bc565b610ca983826000612694565b60006116e482613441565b5092915050565b6000610c858261349b565b600080611701611e61565b611709613600565b6001600160a01b031663d6f32e0684631cd554d160e21b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b15801561176d57600080fd5b505afa158015611781573d6000803e3d6000fd5b505050506040513d602081101561179757600080fd5b5051156117eb576040805162461bcd60e51b815260206004820152601860248201527f73555344206e6565647320746f20626520736574746c65640000000000000000604482015290519081900360640190fd5b6117f3613617565b6001600160a01b031663c49e80a6866040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561184857600080fd5b505afa15801561185c573d6000803e3d6000fd5b505050506040513d602081101561187257600080fd5b50516118c5576040805162461bcd60e51b815260206004820181905260248201527f4163636f756e74206e6f74206f70656e20666f72206c69717569646174696f6e604482015290519081900360640190fd5b631cd554d160e21b600052600560209081527f74c62d09fbc50aefae0794a9a068f786a692826fbdfe63828ec23a875865823f54604080516370a0823160e01b81526001600160a01b0387811660048301529151889492909316926370a0823192602480840193919291829003018186803b15801561194357600080fd5b505afa158015611957573d6000803e3d6000fd5b505050506040513d602081101561196d57600080fd5b505110156119b4576040805162461bcd60e51b815260206004820152600f60248201526e139bdd08195b9bdd59da081cd554d1608a1b604482015290519081900360640190fd5b60006119be613617565b6001600160a01b03166323f5589a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156119f657600080fd5b505afa158015611a0a573d6000803e3d6000fd5b505050506040513d6020811015611a2057600080fd5b5051905060008080611a3989631cd554d160e21b612cbd565b925092509250600080611a4a612bc6565b6001600160a01b0316630c71cd23620a69cb60eb1b6040518263ffffffff1660e01b815260040180828152602001915050604080518083038186803b158015611a9257600080fd5b505afa158015611aa6573d6000803e3d6000fd5b505050506040513d6040811015611abc57600080fd5b5080516020909101519092509050611adb8380611ad65750815b613631565b6000611ae68c61349b565b90506000611af2613617565b6001600160a01b0316630ac045d588611b0b8588613684565b6040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015611b4657600080fd5b505afa158015611b5a573d6000803e3d6000fd5b505050506040513d6020811015611b7057600080fd5b505190508b8110611b81578b611b83565b805b98506000611b918a86613696565b9050611c23611c168a731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611bde57600080fd5b505af4158015611bf2573d6000803e3d6000fd5b505050506040513d6020811015611c0857600080fd5b50519063ffffffff6136a816565b829063ffffffff61370216565b9a50828b1115611c9457829a50611c91611c8b611c7e8b731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611bde57600080fd5b859063ffffffff61372c16565b86613684565b99505b611ca18e8d8c8b8b613756565b50818a1415611d2257611cb2613617565b6001600160a01b031663974e9e7f8f6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050600060405180830381600087803b158015611d0957600080fd5b505af1158015611d1d573d6000803e3d6000fd5b505050505b505050505050505050935093915050565b600080611d3f83613441565b915091505b915091565b611d51611e61565b6108f482826000612694565b6000610a93612ea7565b6000610c858261390d565b611d7a611e61565b610d738160006001611eba565b600080611d92613938565b60408051631167f01160e31b81526001600160a01b038781166004830152825193945060009390851692638b3f80889260248082019391829003018186803b158015611ddd57600080fd5b505afa158015611df1573d6000803e3d6000fd5b505050506040513d6040811015611e0757600080fd5b5051905080611e1b57600092505050610c85565b611e258585612cbd565b50909695505050505050565b60045490565b6000610c8582613954565b611e4a611e61565b611e54828261298e565b6108f48260006001611eba565b611e69613a38565b6001600160a01b0316336001600160a01b031614611eb85760405162461bcd60e51b815260040180806020018281038252603b81526020018061463f603b913960400191505060405180910390fd5b565b600080600080611ec9876124aa565b9350935093509350611eda81613631565b84611f2c5783861115611f27576040805162461bcd60e51b815260206004820152601060248201526f416d6f756e7420746f6f206c6172676560801b604482015290519081900360640190fd5b611f30565b8395505b611f3c87878585613a4f565b611f4587613e24565b631cd554d160e21b600090815260056020527f74c62d09fbc50aefae0794a9a068f786a692826fbdfe63828ec23a875865823f546040805163219e412d60e21b81526001600160a01b038b81166004830152602482018b90529151919092169263867904b4926044808201939182900301818387803b158015611fc757600080fd5b505af1158015611fdb573d6000803e3d6000fd5b50505050611fe76121d8565b6001600160a01b031663d685743a631cd554d160e21b731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561204157600080fd5b505af4158015612055573d6000803e3d6000fd5b505050506040513d602081101561206b57600080fd5b5051604080516001600160e01b031960e086901b1681526004810193909352602483019190915251604480830192600092919082900301818387803b1580156120b357600080fd5b505af11580156120c7573d6000803e3d6000fd5b50505050610d5587613ed6565b6000806000806120e2612bc6565b6001600160a01b0316630c71cd23620a69cb60eb1b6040518263ffffffff1660e01b815260040180828152602001915050604080518083038186803b15801561212a57600080fd5b505afa15801561213e573d6000803e3d6000fd5b505050506040513d604081101561215457600080fd5b508051602090910151909250905060006121766121708761349b565b84613684565b9050612183611c16612ea7565b94509092505050915091565b6000546001600160a01b03163314611eb85760405162461bcd60e51b815260040180806020018281038252602f81526020018061467a602f913960400191505060405180910390fd5b6000610a936844656274436163686560b81b613fce565b6000818152600560205260409020546001600160a01b031680612250576040805162461bcd60e51b815260206004820152601460248201527314de5b9d1a08191bd95cc81b9bdd08195e1a5cdd60621b604482015290519081900360640190fd5b806001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561228957600080fd5b505afa15801561229d573d6000803e3d6000fd5b505050506040513d60208110156122b357600080fd5b5051156122fd576040805162461bcd60e51b815260206004820152601360248201527253796e746820737570706c792065786973747360681b604482015290519081900360640190fd5b631cd554d160e21b82141561234f576040805162461bcd60e51b8152602060048201526013602482015272086c2dcdcdee840e4cadadeecca40e6f2dce8d606b1b604482015290519081900360640190fd5b60005b60045481101561243657816001600160a01b03166004828154811061237357fe5b6000918252602090912001546001600160a01b0316141561242e576004818154811061239b57fe5b600091825260209091200180546001600160a01b03191690556004805460001981019081106123c657fe5b600091825260209091200154600480546001600160a01b0390921691839081106123ec57fe5b600091825260209091200180546001600160a01b0319166001600160a01b039290921691909117905560048054906124289060001983016145cc565b50612436565b600101612352565b506001600160a01b0381166000818152600660209081526040808320839055858352600582529182902080546001600160a01b031916905581518581529081019290925280517f6166f5c475cc1cd535c6cdf14a6d5edb811e34117031fc2863392a136eb655d09281900390910190a15050565b6000806000806124c185631cd554d160e21b612cbd565b919450925090506000806124d4876120d4565b9150915081955082806124e45750805b92508585106124f65760009550612509565b612506868663ffffffff612f3916565b95505b50509193509193565b600061251c6140ab565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6f6d696e696d756d5374616b6554696d6560801b6040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561258b57600080fd5b505afa15801561259f573d6000803e3d6000fd5b505050506040513d60208110156125b557600080fd5b5051905090565b6125c46140c8565b60408051633e9f85d160e11b81526001600160a01b038581166004830152848116602483015291519290911691637d3f0ba291604480820192602092909190829003018186803b15801561261757600080fd5b505afa15801561262b573d6000803e3d6000fd5b505050506040513d602081101561264157600080fd5b50516108f4576040805162461bcd60e51b815260206004820152601d60248201527f4e6f7420617070726f76656420746f20616374206f6e20626568616c66000000604482015290519081900360640190fd5b80612845576126a28361390d565b6126f3576040805162461bcd60e51b815260206004820152601e60248201527f4d696e696d756d207374616b652074696d65206e6f7420726561636865640000604482015290519081900360640190fd5b6000806126fe613600565b6001600160a01b0316631b16802c86631cd554d160e21b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050606060405180830381600087803b15801561276457600080fd5b505af1158015612778573d6000803e3d6000fd5b505050506040513d606081101561278e57600080fd5b50602081015160409091015190925090508015612842576127ad613600565b60408051630984d1f960e31b81526001600160a01b038881166004830152631cd554d160e21b6024830152604482018890526064820186905291519290911691634c268fc891608480820192602092909190829003018186803b15801561281357600080fd5b505afa158015612827573d6000803e3d6000fd5b505050506040513d602081101561283d57600080fd5b505193505b50505b600080600061285b86631cd554d160e21b612cbd565b92509250925060008061286d886120d4565b915091506128818380611ad6575081613631565b600085116128cb576040805162461bcd60e51b81526020600482015260126024820152714e6f206465627420746f20666f726769766560701b604482015290519081900360640190fd5b85156128e4576128e1858363ffffffff612f3916565b96505b60006128f3898a8a8989613756565b905082612906878363ffffffff612f3916565b1161298357612913613617565b6001600160a01b031663974e9e7f8a6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050600060405180830381600087803b15801561296a57600080fd5b505af115801561297e573d6000803e3d6000fd5b505050505b505050505050505050565b6129966140c8565b60408051630487261760e01b81526001600160a01b038581166004830152848116602483015291519290911691630487261791604480820192602092909190829003018186803b15801561261757600080fd5b6000816001600160a01b031663dbd06c856040518163ffffffff1660e01b815260040160206040518083038186803b158015612a2457600080fd5b505afa158015612a38573d6000803e3d6000fd5b505050506040513d6020811015612a4e57600080fd5b50516000818152600560205260409020549091506001600160a01b031615612aac576040805162461bcd60e51b815260206004820152600c60248201526b53796e74682065786973747360a01b604482015290519081900360640190fd5b6001600160a01b03821660009081526006602052604090205415612b17576040805162461bcd60e51b815260206004820152601c60248201527f53796e7468206164647265737320616c72656164792065786973747300000000604482015290519081900360640190fd5b60048054600181019091557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0180546001600160a01b0384166001600160a01b03199182168117909255600083815260056020908152604080832080549094168517909355838252600681529082902084905581518481529081019290925280517f0a2b6ebf143b3e9fcd67e17748ad315174746100c27228468b2c98c302c628849281900390910190a15050565b6000610a936c45786368616e6765526174657360981b613fce565b60608082612bf0576000612bf3565b60015b60ff1660048054905001604051908082528060200260200182016040528015612c26578160200160208202803883390190505b50905060005b600454811015612c8d576006600060048381548110612c4757fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020548251839083908110612c7a57fe5b6020908102919091010152600101612c2c565b508215610c85576004548151620a69cb60eb1b9183918110612cab57fe5b60200260200101818152505092915050565b600080600080612ccb613938565b9050600080826001600160a01b0316638b3f8088896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050604080518083038186803b158015612d2557600080fd5b505afa158015612d39573d6000803e3d6000fd5b505050506040513d6040811015612d4f57600080fd5b5080516020909101519092509050612d68876001612f96565b909550935081612d7f575060009450612ea0915050565b6000612e7c83612e70866001600160a01b03166308d95cd5866040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015612dcc57600080fd5b505afa158015612de0573d6000803e3d6000fd5b505050506040513d6020811015612df657600080fd5b505160408051632318bb8960e11b815290516001600160a01b038a16916346317712916004808301926020929190829003018186803b158015612e3857600080fd5b505afa158015612e4c573d6000803e3d6000fd5b505050506040513d6020811015612e6257600080fd5b50519063ffffffff6140e716565b9063ffffffff61410016565b90506000612e8d82612e7089614119565b9050612e988161412f565b975050505050505b9250925092565b6000612eb16140ab565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6c69737375616e6365526174696f60981b6040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561258b57600080fd5b6000612f328383670de0b6b3a7640000614151565b9392505050565b600082821115612f90576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000806000806000612fa66121d8565b6001600160a01b0316633a900a2e6040518163ffffffff1660e01b815260040160806040518083038186803b158015612fde57600080fd5b505afa158015612ff2573d6000803e3d6000fd5b505050506040513d608081101561300857600080fd5b5080516040820151606090920151909450909250905081806130275750805b93506000613033612bc6565b90508661327757600080613045614189565b6001600160a01b0316631e33fc6b6040518163ffffffff1660e01b8152600401604080518083038186803b15801561307c57600080fd5b505afa158015613090573d6000803e3d6000fd5b505050506040513d60408110156130a657600080fd5b50805160209091015190925090506130c4868363ffffffff6136a816565b955086806130cf5750805b965061314d6130dc6141a8565b6001600160a01b031663ee5f3f5c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561311457600080fd5b505afa158015613128573d6000803e3d6000fd5b505050506040513d602081101561313e57600080fd5b5051879063ffffffff6136a816565b9550600080846001600160a01b0316630c71cd23630e68aa8960e31b6040518263ffffffff1660e01b815260040180828152602001915050604080518083038186803b15801561319c57600080fd5b505afa1580156131b0573d6000803e3d6000fd5b505050506040513d60408110156131c657600080fd5b50805160209091015190925090506000613252836131e26141c9565b6001600160a01b031663ee5f3f5c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561321a57600080fd5b505afa15801561322e573d6000803e3d6000fd5b505050506040513d602081101561324457600080fd5b50519063ffffffff6141e616565b9050613264898263ffffffff6136a816565b9850898061326f5750815b995050505050505b631cd554d160e21b8814156132925750919350613334915050565b600080826001600160a01b0316630c71cd238b6040518263ffffffff1660e01b815260040180828152602001915050604080518083038186803b1580156132d857600080fd5b505afa1580156132ec573d6000803e3d6000fd5b505050506040513d604081101561330257600080fd5b5080516020909101519092509050613320868363ffffffff612f1d16565b87806133295750815b975097505050505050505b9250929050565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b8160008151811061337d57fe5b60200260200101818152505090565b606081518351016040519080825280602002602001820160405280156133bc578160200160208202803883390190505b50905060005b83518110156133fe578381815181106133d757fe5b60200260200101518282815181106133eb57fe5b60209081029190910101526001016133c2565b5060005b82518110156116e45782818151811061341757fe5b602002602001015182828651018151811061342e57fe5b6020908102919091010152600101613402565b600080600061344f8461349b565b905060008061346486620a69cb60eb1b612cbd565b9250509150826000141561348057600094509250611d44915050565b613490828463ffffffff612f1d16565b945092505050915091565b6000806134a6613a38565b6001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156134fb57600080fd5b505afa15801561350f573d6000803e3d6000fd5b505050506040513d602081101561352557600080fd5b5051905060006135336141fb565b6001600160a01b0316146135dd576135da61354c6141fb565b6001600160a01b03166370a08231856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156135a157600080fd5b505afa1580156135b5573d6000803e3d6000fd5b505050506040513d60208110156135cb57600080fd5b5051829063ffffffff6136a816565b90505b60006135e7614218565b6001600160a01b031614610c8557612f3261354c614218565b6000610a936822bc31b430b733b2b960b91b613fce565b6000610a936b4c69717569646174696f6e7360a01b613fce565b8015610d73576040805162461bcd60e51b815260206004820152601e60248201527f412073796e7468206f7220534e58207261746520697320696e76616c69640000604482015290519081900360640190fd5b6000612f32838363ffffffff6141e616565b6000612f32838363ffffffff612f1d16565b600082820183811015612f32576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000670de0b6b3a764000061371d848463ffffffff61423416565b8161372457fe5b049392505050565b6000612f328261374a85670de0b6b3a764000063ffffffff61423416565b9063ffffffff61428d16565b60008383106137655783613767565b825b9050613775868285856142f7565b631cd554d160e21b600090815260056020527f74c62d09fbc50aefae0794a9a068f786a692826fbdfe63828ec23a875865823f5460408051632770a7eb60e21b81526001600160a01b0389811660048301526024820186905291519190921692639dc29fac926044808201939182900301818387803b1580156137f757600080fd5b505af115801561380b573d6000803e3d6000fd5b505050506138176121d8565b6001600160a01b031663d685743a631cd554d160e21b731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561387157600080fd5b505af4158015613885573d6000803e3d6000fd5b505050506040513d602081101561389b57600080fd5b5051604080516001600160e01b031960e086901b1681526004810193909352602483019190915251604480830192600092919082900301818387803b1580156138e357600080fd5b505af11580156138f7573d6000803e3d6000fd5b5050505061390486613ed6565b95945050505050565b600061392f61391a612512565b61392384613954565b9063ffffffff6136a816565b42101592915050565b6000610a936d53796e746865746978537461746560901b613fce565b600061395e6140ab565b6001600160a01b03166323257c2b6524b9b9bab2b960d11b6d1b185cdd125cdcdd59515d995b9d60921b8560405160200180838152602001826001600160a01b03166001600160a01b031660601b815260140192505050604051602081830303815290604052805190602001206040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015613a0657600080fd5b505afa158015613a1a573d6000803e3d6000fd5b505050506040513d6020811015613a3057600080fd5b505192915050565b6000610a93680a6f2dce8d0cae8d2f60bb1b613fce565b6000613a59613938565b90506000613a6d858463ffffffff6136a816565b90506000613a81868363ffffffff6140e716565b90506000613b0582731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63d5e5e6e66040518163ffffffff1660e01b815260040160206040518083038186803b158015613acd57600080fd5b505af4158015613ae1573d6000803e3d6000fd5b505050506040513d6020811015613af757600080fd5b50519063ffffffff612f3916565b90508515613b3457613b2d83613b21898963ffffffff6136a816565b9063ffffffff6140e716565b9150613b88565b836001600160a01b0316631bfba5956040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613b6f57600080fd5b505af1158015613b83573d6000803e3d6000fd5b505050505b836001600160a01b031663a764eb4589846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613be857600080fd5b505af1158015613bfc573d6000803e3d6000fd5b505050506000846001600160a01b031663cd92eba96040518163ffffffff1660e01b815260040160206040518083038186803b158015613c3b57600080fd5b505afa158015613c4f573d6000803e3d6000fd5b505050506040513d6020811015613c6557600080fd5b50511115613d4457836001600160a01b0316633d31e97b613cf183876001600160a01b031663463177126040518163ffffffff1660e01b815260040160206040518083038186803b158015613cb957600080fd5b505afa158015613ccd573d6000803e3d6000fd5b505050506040513d6020811015613ce357600080fd5b50519063ffffffff61410016565b6040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613d2757600080fd5b505af1158015613d3b573d6000803e3d6000fd5b50505050613e1a565b836001600160a01b0316633d31e97b731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63d5e5e6e66040518163ffffffff1660e01b815260040160206040518083038186803b158015613d9757600080fd5b505af4158015613dab573d6000803e3d6000fd5b505050506040513d6020811015613dc157600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015613e0157600080fd5b505af1158015613e15573d6000803e3d6000fd5b505050505b5050505050505050565b613e2c6140ab565b604080516d1b185cdd125cdcdd59515d995b9d60921b6020808301919091526bffffffffffffffffffffffff19606086901b1682840152825160348184030181526054830180855281519190920120631d5b277f60e01b9091526524b9b9bab2b960d11b6058830152607882015242609882015290516001600160a01b039290921691631d5b277f9160b88082019260009290919082900301818387803b15801561142957600080fd5b600080613ee1613938565b60408051631167f01160e31b81526001600160a01b0386811660048301528251931692638b3f808892602480840193919291829003018186803b158015613f2757600080fd5b505afa158015613f3b573d6000803e3d6000fd5b505050506040513d6040811015613f5157600080fd5b5080516020909101519092509050613f6761458c565b6001600160a01b031663866452748484846040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b031681526020018381526020018281526020019350505050600060405180830381600087803b158015610d4157600080fd5b600081815260036020908152604080832054815170026b4b9b9b4b7339030b2323932b9b99d1607d1b9381019390935260318084018690528251808503909101815260519093019091526001600160a01b031690816116e45760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614070578181015183820152602001614058565b50505050905090810190601f16801561409d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6000610a936e466c657869626c6553746f7261676560881b613fce565b6000610a937044656c6567617465417070726f76616c7360781b613fce565b6000612f3283836b033b2e3c9fd0803ce8000000614151565b6000612f3283836b033b2e3c9fd0803ce80000006145a1565b6000610c8582633b9aca0063ffffffff61423416565b60006305f5e10082046005600a82061061414757600a015b600a900492915050565b60008061416b8461374a87600a870263ffffffff61423416565b90506005600a825b061061417d57600a015b600a9004949350505050565b6000610a937021b7b63630ba32b930b626b0b730b3b2b960791b613fce565b6000610a9372115d1a195c90dbdb1b185d195c985b1cd554d1606a1b613fce565b6000610a936e115d1a195c90dbdb1b185d195c985b608a1b613fce565b6000612f328383670de0b6b3a76400006145a1565b6000610a936e53796e746865746978457363726f7760881b613fce565b6000610a936d2932bbb0b93222b9b1b937bbab1960911b613fce565b60008261424357506000610c85565b8282028284828161425057fe5b0414612f325760405162461bcd60e51b81526004018080602001828103825260218152602001806146a96021913960400191505060405180910390fd5b60008082116142e3576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b60008284816142ee57fe5b04949350505050565b6000614301613938565b90506000614315838663ffffffff612f3916565b90506000811561437f576000614331878463ffffffff6140e716565b905061437b81731a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c63d5e5e6e66040518163ffffffff1660e01b815260040160206040518083038186803b158015611bde57600080fd5b9150505b84861415614446576040805163a764eb4560e01b81526001600160a01b03898116600483015260006024830181905292519086169263a764eb45926044808201939182900301818387803b1580156143d657600080fd5b505af11580156143ea573d6000803e3d6000fd5b50505050826001600160a01b031663ba08f2996040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561442957600080fd5b505af115801561443d573d6000803e3d6000fd5b505050506144e9565b6000614458868863ffffffff612f3916565b9050600061446c828563ffffffff6140e716565b9050846001600160a01b031663a764eb458a836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156144ce57600080fd5b505af11580156144e2573d6000803e3d6000fd5b5050505050505b826001600160a01b0316633d31e97b61453583866001600160a01b031663463177126040518163ffffffff1660e01b815260040160206040518083038186803b158015613cb957600080fd5b6040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561456b57600080fd5b505af115801561457f573d6000803e3d6000fd5b5050505050505050505050565b6000610a9366119959541bdbdb60ca1b613fce565b600080600a83046145b8868663ffffffff61423416565b816145bf57fe5b0490506005600a82614173565b815481835581811115610ca957600083815260209020610ca9918101908301610a9691905b8082111561460557600081556001016145f1565b509056fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e6572736869704973737565723a204f6e6c79207468652073796e74686574697820636f6e74726163742063616e20706572666f726d207468697320616374696f6e4f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a723158206faced0d6f9a4bf1dd862966aecc2c607a62d8905057a5d924d5657c3ffa342d64736f6c63430005100032000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2

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

000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2

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

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882
Arg [1] : 000000000000000000000000242a3df52c375bee81b1c668741d7c63af68fdd2


Library Used

SafeDecimalMath : 0x1a60e2e2a8be0bc2b6381dd31fd3fd5f9a28de4c

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