Contract 0xa0D797A7f805B2eCA06dD5680Ee07eDbbcDEBc94

Contract Overview

Balance:
0 Ether
Txn Hash Method
Block
From
To
Value
0x756922c13b973e34bab15420bc02ef6cdc8b6d43e879067fb9627e2961d3d089Update Rates100455762021-04-15 15:15:032 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0114494310
0xda0bd63a034ee1ab51bf49d16dd15386483fb448a90a7d9ba4518210e2e34ff4Update Rates100455672021-04-15 15:12:125 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0105882110
0x847c524a60ebe7451a3476852289e90c7c74269f8a5a1b56d0f17718f14a22e9Update Rates100455512021-04-15 15:09:078 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0110226910
0x99db355640832a9e27e4b5a2afa455c4bb859a5a4cfb94f24d5a175b55e067d2Update Rates100455392021-04-15 15:06:0311 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0127389810
0xe40977031aa6e7ca3c9d4bf124c831ad51d4d7797688632412cb09be1c160156Update Rates100455232021-04-15 15:03:0014 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0105866210
0x14f501b5a6a571d13ac792373745428afe4f5ecf4fc19fe63701ef9e4c9d2eacUpdate Rates100455042021-04-15 15:00:0017 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0110193810
0x7b17cc84be77c1f1d69e2eaeb47a6074a20f0feee706567a8159aa0525bda472Update Rates100454902021-04-15 14:57:2819 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0101588110
0xe09642d4531908a13aaa3e3c2aabbb654ee7fd1d7a04542fa31ef84b7d67458eUpdate Rates100454742021-04-15 14:54:0223 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0110222110
0xe0e223f07495ebf61873834fa6709fd9b22e21f53e0c54c40cc8f4d45a21c237Update Rates100454542021-04-15 14:51:0726 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.009726110
0x9eb33c2fb9de2ebcc8567e9ab66f00e29a3d688b2044269afb2cd57415ae7634Update Rates100454392021-04-15 14:46:4130 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0097299510
0xc4560a10b1640429b0eb4f09645cfbbfaaf7b7ac291131627a271038a8db7489Update Rates100454332021-04-15 14:45:2331 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0084386210
0x2b423b342cac7d633f33125f9d171c2544be27821ef500e3033c079a7a5d74ebUpdate Rates100454232021-04-15 14:42:0635 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0058563110
0x8ec6626af5d461270b2c8883aa4f6605b9d544d440034d64a0c68ec5e0607604Update Rates100454112021-04-15 14:39:1438 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0118823510
0x50ead2aded0df93b9d6b9dd0d7a73a07ab1beb04e73d2b94cc0dad9a1a036cc8Update Rates100453982021-04-15 14:35:5941 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0084397310
0x2237b24222ddb602a622d8b942c8298e336db88430426cc2a234d861ac12088bUpdate Rates100453832021-04-15 14:32:4444 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0136018910
0x7dfbc0e0ee8fa80e21da16808fb72275e035736e66170a2da08bea7b3b97984eUpdate Rates100453622021-04-15 14:26:5950 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.009297510
0xa3450080c6f630660c55d8832ca6c985fa4ea4c1aae1fe3e49cf6953855449caUpdate Rates100453532021-04-15 14:24:2053 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0097263410
0xc95ea41fae5548e4fe93ee02df256cab84f104fa26014f52a746e22dfa2a4eb1Update Rates100453402021-04-15 14:21:1556 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0088694210
0x15a001e79090a7938c1cd3b86dd760d93a94a6e0ba892debdc32be55f8988a3dUpdate Rates100453192021-04-15 14:18:0159 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0114489210
0xc06bf4b46002edcca54e6a877d43a01c138f393701d0339f6221301db6396718Update Rates100453012021-04-15 14:15:251 hr 1 min ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0062858710
0x46ceac6d330b922817a971d50d076e8d5d02f6edf4a26cb5350a1b97ff750b92Update Rates100452812021-04-15 14:12:051 hr 5 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0110201310
0xc22168391346a3155fc700e0965e18dea1be885228aefb26eaed9f2eba0aa9d5Update Rates100452682021-04-15 14:08:441 hr 8 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0114497910
0x10b1997d595686031d3be4955cd0c0bd2c426e1a831fbdbbd71596ec962ee0b5Update Rates100452612021-04-15 14:06:031 hr 11 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0105882110
0x4fb174265eafeef2c20482176f0fa3f3a02879ec750f512eaf2ec60668327801Update Rates100452522021-04-15 14:03:221 hr 14 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0049956810
0x0004304b4666a2a305f73fe5579093aefa3a2271f77bb6742e8a2f95e65bc66cUpdate Rates100452372021-04-15 13:59:581 hr 17 mins ago0xac1e8b385230970319906c03a1d8567e3996d1d5 IN  0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether0.0097268510
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x95579a8376ffd7d66acdc1ec9992b7fedcb658540 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x95579a8376ffd7d66acdc1ec9992b7fedcb658540 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xcc3a7753ee8a5c5969b068ed35eb5110b0c611a70 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xcc3a7753ee8a5c5969b068ed35eb5110b0c611a70 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x6021c0ab48dda82a81f83276af123e0bd89edcf30 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x6021c0ab48dda82a81f83276af123e0bd89edcf30 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x09340ffcd275735c4dfef24d21017d5b1cbd00fd0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x09340ffcd275735c4dfef24d21017d5b1cbd00fd0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x0c1db240827677264e89aa6c0cc35c78bcc457990 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x0c1db240827677264e89aa6c0cc35c78bcc457990 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xa8ce4412fb92fc5f6257197b229fe75a8c2e1e580 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xa8ce4412fb92fc5f6257197b229fe75a8c2e1e580 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x1e5a19e9f382dd254d6983ff253a64f0bf15058a0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x1e5a19e9f382dd254d6983ff253a64f0bf15058a0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x795122664e4d4a3f7e66e8674953c97adc60b17c0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x795122664e4d4a3f7e66e8674953c97adc60b17c0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xa28a03a00cefe08d68025044fefac221cbee8a550 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xa28a03a00cefe08d68025044fefac221cbee8a550 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x7cb0caefe0321880367013bb76acb843db412d3d0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x7cb0caefe0321880367013bb76acb843db412d3d0 Ether
0xbf3e19a115cf2bcfb1cc71e940c114116dfdddb8fa84181a3104f9aa65f2a5ff100330372021-04-13 18:19:461 day 20 hrs ago 0xba46d4cd44c9eb5f2d5a2c72d53add0782b3806f 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc940 Ether
0xdf915d26456905bf0346a75e925b18bde661836e089f8dba3cfe94f858e96c9b100330072021-04-13 18:13:531 day 21 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x95579a8376ffd7d66acdc1ec9992b7fedcb658540 Ether
0xdf915d26456905bf0346a75e925b18bde661836e089f8dba3cfe94f858e96c9b100330072021-04-13 18:13:531 day 21 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0x95579a8376ffd7d66acdc1ec9992b7fedcb658540 Ether
0xdf915d26456905bf0346a75e925b18bde661836e089f8dba3cfe94f858e96c9b100330072021-04-13 18:13:531 day 21 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xcc3a7753ee8a5c5969b068ed35eb5110b0c611a70 Ether
0xdf915d26456905bf0346a75e925b18bde661836e089f8dba3cfe94f858e96c9b100330072021-04-13 18:13:531 day 21 hrs ago 0xa0d797a7f805b2eca06dd5680ee07edbbcdebc94 0xcc3a7753ee8a5c5969b068ed35eb5110b0c611a70 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ExchangeRates

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 20000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-08-31
*/

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

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



pragma solidity ^0.5.16;


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

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

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

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

    modifier onlyOwner {
        require(msg.sender == owner, "Only the contract owner may perform this action");
        _;
    }

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


// Inheritance


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

    uint public initiationTime;
    bool public selfDestructInitiated;

    address public selfDestructBeneficiary;

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

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

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

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

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

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


interface IAddressResolver {
    function getAddress(bytes32 name) external view returns (address);

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

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


interface ISynth {
    // Views
    function currencyKey() external view returns (bytes32);

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

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

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

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

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


interface 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 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


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

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

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

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

        for (uint i = 0; i < names.length; i++) {
            repository[names[i]] = destinations[i];
        }
    }

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

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

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

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


// Inheritance


// Internal references


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

    mapping(bytes32 => address) private addressCache;

    bytes32[] public resolverAddressesRequired;

    uint public constant MAX_ADDRESSES_FROM_RESOLVER = 24;

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

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

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

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

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

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

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

        // otherwise, check everything
        for (uint i = 0; i < resolverAddressesRequired.length; i++) {
            bytes32 name = resolverAddressesRequired[i];
            // false if our cache is invalid or if the resolver doesn't have the required address
            if (resolver.getAddress(name) != addressCache[name] || addressCache[name] == address(0)) {
                return false;
            }
        }

        return true;
    }

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

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


interface 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


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 private constant CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage";

    constructor() internal {
        appendToAddressCache(CONTRACT_FLEXIBLESTORAGE);
    }

    function flexibleStorage() internal view returns (IFlexibleStorage) {
        return IFlexibleStorage(requireAndGetAddress(CONTRACT_FLEXIBLESTORAGE, "Missing FlexibleStorage address"));
    }

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


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


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

        return c;
    }

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

        return c;
    }

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

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

        return c;
    }

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

        return c;
    }

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


// Libraries


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

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

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

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

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

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

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

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

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

        return quotientTimesTen / 10;
    }

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

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

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

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

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

        return resultTimesTen / 10;
    }

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

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

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

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

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

        return quotientTimesTen / 10;
    }
}


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

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


interface FlagsInterface {
  function getFlag(address) external view returns (bool);
  function getFlags(address[] calldata) external view returns (bool[] memory);
  function raiseFlag(address) external;
  function raiseFlags(address[] calldata) external;
  function lowerFlags(address[] calldata) external;
  function setRaisingAccessController(address) external;
}


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


// Inheritance


// Libraries


// Internal references
// AggregatorInterface from Chainlink represents a decentralized pricing network for a single currency key

// FlagsInterface from Chainlink addresses SIP-76


// https://docs.synthetix.io/contracts/source/contracts/ExchangeRates
contract ExchangeRates is Owned, SelfDestructible, MixinResolver, MixinSystemSettings, IExchangeRates {
    using SafeMath for uint;
    using SafeDecimalMath for uint;

    // Exchange rates and update times stored by currency code, e.g. 'SNX', or 'sUSD'
    mapping(bytes32 => mapping(uint => RateAndUpdatedTime)) private _rates;

    // The address of the oracle which pushes rate updates to this contract
    address public oracle;

    // Decentralized oracle networks that feed into pricing aggregators
    mapping(bytes32 => AggregatorInterface) public aggregators;

    // List of aggregator keys for convenient iteration
    bytes32[] public aggregatorKeys;

    // Do not allow the oracle to submit times any further forward into the future than this constant.
    uint private constant ORACLE_FUTURE_LIMIT = 10 minutes;

    int private constant AGGREGATOR_RATE_MULTIPLIER = 1e10;

    mapping(bytes32 => InversePricing) public inversePricing;

    bytes32[] public invertedKeys;

    mapping(bytes32 => uint) public currentRoundForRate;

    /* ========== ADDRESS RESOLVER CONFIGURATION ========== */
    bytes32 private constant CONTRACT_EXCHANGER = "Exchanger";

    bytes32[24] private addressesToCache = [CONTRACT_EXCHANGER];

    //
    // ========== CONSTRUCTOR ==========

    constructor(
        address _owner,
        address _oracle,
        address _resolver,
        bytes32[] memory _currencyKeys,
        uint[] memory _newRates
    ) public Owned(_owner) SelfDestructible() MixinResolver(_resolver, addressesToCache) MixinSystemSettings() {
        require(_currencyKeys.length == _newRates.length, "Currency key length and rate length must match.");

        oracle = _oracle;

        // The sUSD rate is always 1 and is never stale.
        _setRate("sUSD", SafeDecimalMath.unit(), now);

        internalUpdateRates(_currencyKeys, _newRates, now);
    }

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

    function setOracle(address _oracle) external onlyOwner {
        oracle = _oracle;
        emit OracleUpdated(oracle);
    }

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

    function updateRates(
        bytes32[] calldata currencyKeys,
        uint[] calldata newRates,
        uint timeSent
    ) external onlyOracle returns (bool) {
        return internalUpdateRates(currencyKeys, newRates, timeSent);
    }

    function deleteRate(bytes32 currencyKey) external onlyOracle {
        require(_getRate(currencyKey) > 0, "Rate is zero");

        delete _rates[currencyKey][currentRoundForRate[currencyKey]];

        currentRoundForRate[currencyKey]--;

        emit RateDeleted(currencyKey);
    }

    function setInversePricing(
        bytes32 currencyKey,
        uint entryPoint,
        uint upperLimit,
        uint lowerLimit,
        bool freezeAtUpperLimit,
        bool freezeAtLowerLimit
    ) external onlyOwner {
        // 0 < lowerLimit < entryPoint => 0 < entryPoint
        require(lowerLimit > 0, "lowerLimit must be above 0");
        require(upperLimit > entryPoint, "upperLimit must be above the entryPoint");
        require(upperLimit < entryPoint.mul(2), "upperLimit must be less than double entryPoint");
        require(lowerLimit < entryPoint, "lowerLimit must be below the entryPoint");

        require(!(freezeAtUpperLimit && freezeAtLowerLimit), "Cannot freeze at both limits");

        InversePricing storage inverse = inversePricing[currencyKey];
        if (inverse.entryPoint == 0) {
            // then we are adding a new inverse pricing, so add this
            invertedKeys.push(currencyKey);
        }
        inverse.entryPoint = entryPoint;
        inverse.upperLimit = upperLimit;
        inverse.lowerLimit = lowerLimit;

        if (freezeAtUpperLimit || freezeAtLowerLimit) {
            // When indicating to freeze, we need to know the rate to freeze it at - either upper or lower
            // this is useful in situations where ExchangeRates is updated and there are existing inverted
            // rates already frozen in the current contract that need persisting across the upgrade

            inverse.frozenAtUpperLimit = freezeAtUpperLimit;
            inverse.frozenAtLowerLimit = freezeAtLowerLimit;
            emit InversePriceFrozen(currencyKey, freezeAtUpperLimit ? upperLimit : lowerLimit, msg.sender);
        } else {
            // unfreeze if need be
            inverse.frozenAtUpperLimit = false;
            inverse.frozenAtLowerLimit = false;
        }

        // SIP-78
        uint rate = _getRate(currencyKey);
        if (rate > 0) {
            exchanger().setLastExchangeRateForSynth(currencyKey, rate);
        }

        emit InversePriceConfigured(currencyKey, entryPoint, upperLimit, lowerLimit);
    }

    function removeInversePricing(bytes32 currencyKey) external onlyOwner {
        require(inversePricing[currencyKey].entryPoint > 0, "No inverted price exists");

        delete inversePricing[currencyKey];

        // now remove inverted key from array
        bool wasRemoved = removeFromArray(currencyKey, invertedKeys);

        if (wasRemoved) {
            emit InversePriceConfigured(currencyKey, 0, 0, 0);
        }
    }

    function addAggregator(bytes32 currencyKey, address aggregatorAddress) external onlyOwner {
        AggregatorInterface aggregator = AggregatorInterface(aggregatorAddress);
        // This check tries to make sure that a valid aggregator is being added.
        // It checks if the aggregator is an existing smart contract that has implemented `latestTimestamp` function.
        require(aggregator.latestTimestamp() >= 0, "Given Aggregator is invalid");
        if (address(aggregators[currencyKey]) == address(0)) {
            aggregatorKeys.push(currencyKey);
        }
        aggregators[currencyKey] = aggregator;
        emit AggregatorAdded(currencyKey, address(aggregator));
    }

    function removeAggregator(bytes32 currencyKey) external onlyOwner {
        address aggregator = address(aggregators[currencyKey]);
        require(aggregator != address(0), "No aggregator exists for key");
        delete aggregators[currencyKey];

        bool wasRemoved = removeFromArray(currencyKey, aggregatorKeys);

        if (wasRemoved) {
            emit AggregatorRemoved(currencyKey, aggregator);
        }
    }

    // SIP-75 Public keeper function to freeze a synth that is out of bounds
    function freezeRate(bytes32 currencyKey) external {
        InversePricing storage inverse = inversePricing[currencyKey];
        require(inverse.entryPoint > 0, "Cannot freeze non-inverse rate");
        require(!inverse.frozenAtUpperLimit && !inverse.frozenAtLowerLimit, "The rate is already frozen");

        uint rate = _getRate(currencyKey);

        if (rate > 0 && (rate >= inverse.upperLimit || rate <= inverse.lowerLimit)) {
            inverse.frozenAtUpperLimit = (rate == inverse.upperLimit);
            inverse.frozenAtLowerLimit = (rate == inverse.lowerLimit);
            emit InversePriceFrozen(currencyKey, rate, msg.sender);
        } else {
            revert("Rate within bounds");
        }
    }

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

    // SIP-75 View to determine if freezeRate can be called safely
    function canFreezeRate(bytes32 currencyKey) external view returns (bool) {
        InversePricing memory inverse = inversePricing[currencyKey];
        if (inverse.entryPoint == 0 || inverse.frozenAtUpperLimit || inverse.frozenAtLowerLimit) {
            return false;
        } else {
            uint rate = _getRate(currencyKey);
            return (rate > 0 && (rate >= inverse.upperLimit || rate <= inverse.lowerLimit));
        }
    }

    function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory currencies) {
        uint count = 0;
        currencies = new bytes32[](aggregatorKeys.length);
        for (uint i = 0; i < aggregatorKeys.length; i++) {
            bytes32 currencyKey = aggregatorKeys[i];
            if (address(aggregators[currencyKey]) == aggregator) {
                currencies[count++] = currencyKey;
            }
        }
    }

    function rateStalePeriod() external view returns (uint) {
        return getRateStalePeriod();
    }

    function aggregatorWarningFlags() external view returns (address) {
        return getAggregatorWarningFlags();
    }

    function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time) {
        RateAndUpdatedTime memory rateAndTime = _getRateAndUpdatedTime(currencyKey);
        return (rateAndTime.rate, rateAndTime.time);
    }

    function getLastRoundIdBeforeElapsedSecs(
        bytes32 currencyKey,
        uint startingRoundId,
        uint startingTimestamp,
        uint timediff
    ) external view returns (uint) {
        uint roundId = startingRoundId;
        uint nextTimestamp = 0;
        while (true) {
            (, nextTimestamp) = _getRateAndTimestampAtRound(currencyKey, roundId + 1);
            // if there's no new round, then the previous roundId was the latest
            if (nextTimestamp == 0 || nextTimestamp > startingTimestamp + timediff) {
                return roundId;
            }
            roundId++;
        }
        return roundId;
    }

    function getCurrentRoundId(bytes32 currencyKey) external view returns (uint) {
        return _getCurrentRoundId(currencyKey);
    }

    function effectiveValueAtRound(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey,
        uint roundIdForSrc,
        uint roundIdForDest
    ) external view returns (uint value) {
        // If there's no change in the currency, then just return the amount they gave us
        if (sourceCurrencyKey == destinationCurrencyKey) return sourceAmount;

        (uint srcRate, ) = _getRateAndTimestampAtRound(sourceCurrencyKey, roundIdForSrc);
        (uint destRate, ) = _getRateAndTimestampAtRound(destinationCurrencyKey, roundIdForDest);
        // Calculate the effective value by going from source -> USD -> destination
        value = sourceAmount.multiplyDecimalRound(srcRate).divideDecimalRound(destRate);
    }

    function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time) {
        return _getRateAndTimestampAtRound(currencyKey, roundId);
    }

    function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256) {
        return _getUpdatedTime(currencyKey);
    }

    function lastRateUpdateTimesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory) {
        uint[] memory lastUpdateTimes = new uint[](currencyKeys.length);

        for (uint i = 0; i < currencyKeys.length; i++) {
            lastUpdateTimes[i] = _getUpdatedTime(currencyKeys[i]);
        }

        return lastUpdateTimes;
    }

    function effectiveValue(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey
    ) external view returns (uint value) {
        (value, , ) = _effectiveValueAndRates(sourceCurrencyKey, sourceAmount, destinationCurrencyKey);
    }

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

    function rateForCurrency(bytes32 currencyKey) external view returns (uint) {
        return _getRateAndUpdatedTime(currencyKey).rate;
    }

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

        uint roundId = _getCurrentRoundId(currencyKey);
        for (uint i = 0; i < numRounds; i++) {
            (rates[i], times[i]) = _getRateAndTimestampAtRound(currencyKey, roundId);
            if (roundId == 0) {
                // if we hit the last round, then return what we have
                return (rates, times);
            } else {
                roundId--;
            }
        }
    }

    function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory) {
        uint[] memory _localRates = new uint[](currencyKeys.length);

        for (uint i = 0; i < currencyKeys.length; i++) {
            _localRates[i] = _getRate(currencyKeys[i]);
        }

        return _localRates;
    }

    function ratesAndInvalidForCurrencies(bytes32[] calldata currencyKeys)
        external
        view
        returns (uint[] memory rates, bool anyRateInvalid)
    {
        rates = new uint[](currencyKeys.length);

        uint256 _rateStalePeriod = getRateStalePeriod();

        // fetch all flags at once
        bool[] memory flagList = getFlagsForRates(currencyKeys);

        for (uint i = 0; i < currencyKeys.length; i++) {
            // do one lookup of the rate & time to minimize gas
            RateAndUpdatedTime memory rateEntry = _getRateAndUpdatedTime(currencyKeys[i]);
            rates[i] = rateEntry.rate;
            if (!anyRateInvalid && currencyKeys[i] != "sUSD") {
                anyRateInvalid = flagList[i] || _rateIsStaleWithTime(_rateStalePeriod, rateEntry.time);
            }
        }
    }

    function rateIsStale(bytes32 currencyKey) external view returns (bool) {
        return _rateIsStale(currencyKey, getRateStalePeriod());
    }

    function rateIsFrozen(bytes32 currencyKey) external view returns (bool) {
        return _rateIsFrozen(currencyKey);
    }

    function rateIsInvalid(bytes32 currencyKey) external view returns (bool) {
        return
            _rateIsStale(currencyKey, getRateStalePeriod()) ||
            _rateIsFlagged(currencyKey, FlagsInterface(getAggregatorWarningFlags()));
    }

    function rateIsFlagged(bytes32 currencyKey) external view returns (bool) {
        return _rateIsFlagged(currencyKey, FlagsInterface(getAggregatorWarningFlags()));
    }

    function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool) {
        // Loop through each key and check whether the data point is stale.

        uint256 _rateStalePeriod = getRateStalePeriod();
        bool[] memory flagList = getFlagsForRates(currencyKeys);

        for (uint i = 0; i < currencyKeys.length; i++) {
            if (flagList[i] || _rateIsStale(currencyKeys[i], _rateStalePeriod)) {
                return true;
            }
        }

        return false;
    }

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

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

    function getFlagsForRates(bytes32[] memory currencyKeys) internal view returns (bool[] memory flagList) {
        FlagsInterface _flags = FlagsInterface(getAggregatorWarningFlags());

        // fetch all flags at once
        if (_flags != FlagsInterface(0)) {
            address[] memory _aggregators = new address[](currencyKeys.length);

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

            flagList = _flags.getFlags(_aggregators);
        } else {
            flagList = new bool[](currencyKeys.length);
        }
    }

    function _setRate(
        bytes32 currencyKey,
        uint256 rate,
        uint256 time
    ) internal {
        // Note: this will effectively start the rounds at 1, which matches Chainlink's Agggregators
        currentRoundForRate[currencyKey]++;

        _rates[currencyKey][currentRoundForRate[currencyKey]] = RateAndUpdatedTime({
            rate: uint216(rate),
            time: uint40(time)
        });
    }

    function internalUpdateRates(
        bytes32[] memory currencyKeys,
        uint[] memory newRates,
        uint timeSent
    ) internal returns (bool) {
        require(currencyKeys.length == newRates.length, "Currency key array length must match rates array length.");
        require(timeSent < (now + ORACLE_FUTURE_LIMIT), "Time is too far into the future");

        // Loop through each key and perform update.
        for (uint i = 0; i < currencyKeys.length; i++) {
            bytes32 currencyKey = currencyKeys[i];

            // Should not set any rate to zero ever, as no asset will ever be
            // truely worthless and still valid. In this scenario, we should
            // delete the rate and remove it from the system.
            require(newRates[i] != 0, "Zero is not a valid rate, please call deleteRate instead.");
            require(currencyKey != "sUSD", "Rate of sUSD cannot be updated, it's always UNIT.");

            // We should only update the rate if it's at least the same age as the last rate we've got.
            if (timeSent < _getUpdatedTime(currencyKey)) {
                continue;
            }

            // Ok, go ahead with the update.
            _setRate(currencyKey, newRates[i], timeSent);
        }

        emit RatesUpdated(currencyKeys, newRates);

        return true;
    }

    function removeFromArray(bytes32 entry, bytes32[] storage array) internal returns (bool) {
        for (uint i = 0; i < array.length; i++) {
            if (array[i] == entry) {
                delete array[i];

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

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

                return true;
            }
        }
        return false;
    }

    function _rateOrInverted(bytes32 currencyKey, uint rate) internal view returns (uint newRate) {
        // if an inverse mapping exists, adjust the price accordingly
        InversePricing memory inverse = inversePricing[currencyKey];
        if (inverse.entryPoint == 0 || rate == 0) {
            // when no inverse is set or when given a 0 rate, return the rate, regardless of the inverse status
            // (the latter is so when a new inverse is set but the underlying has no rate, it will return 0 as
            // the rate, not the lowerLimit)
            return rate;
        }

        newRate = rate;

        // These cases ensures that if a price has been frozen, it stays frozen even if it returns to the bounds
        if (inverse.frozenAtUpperLimit) {
            newRate = inverse.upperLimit;
        } else if (inverse.frozenAtLowerLimit) {
            newRate = inverse.lowerLimit;
        } else {
            // this ensures any rate outside the limit will never be returned
            uint doubleEntryPoint = inverse.entryPoint.mul(2);
            if (doubleEntryPoint <= rate) {
                // avoid negative numbers for unsigned ints, so set this to 0
                // which by the requirement that lowerLimit be > 0 will
                // cause this to freeze the price to the lowerLimit
                newRate = 0;
            } else {
                newRate = doubleEntryPoint.sub(rate);
            }

            // now ensure the rate is between the bounds
            if (newRate >= inverse.upperLimit) {
                newRate = inverse.upperLimit;
            } else if (newRate <= inverse.lowerLimit) {
                newRate = inverse.lowerLimit;
            }
        }
    }

    function _getRateAndUpdatedTime(bytes32 currencyKey) internal view returns (RateAndUpdatedTime memory) {
        AggregatorInterface aggregator = aggregators[currencyKey];

        if (aggregator != AggregatorInterface(0)) {
            return
                RateAndUpdatedTime({
                    rate: uint216(
                        _rateOrInverted(currencyKey, uint(aggregator.latestAnswer() * AGGREGATOR_RATE_MULTIPLIER))
                    ),
                    time: uint40(aggregator.latestTimestamp())
                });
        } else {
            RateAndUpdatedTime memory entry = _rates[currencyKey][currentRoundForRate[currencyKey]];

            return RateAndUpdatedTime({rate: uint216(_rateOrInverted(currencyKey, entry.rate)), time: entry.time});
        }
    }

    function _getCurrentRoundId(bytes32 currencyKey) internal view returns (uint) {
        AggregatorInterface aggregator = aggregators[currencyKey];

        if (aggregator != AggregatorInterface(0)) {
            return aggregator.latestRound();
        } else {
            return currentRoundForRate[currencyKey];
        }
    }

    function _getRateAndTimestampAtRound(bytes32 currencyKey, uint roundId) internal view returns (uint rate, uint time) {
        AggregatorInterface aggregator = aggregators[currencyKey];

        if (aggregator != AggregatorInterface(0)) {
            return (
                _rateOrInverted(currencyKey, uint(aggregator.getAnswer(roundId) * AGGREGATOR_RATE_MULTIPLIER)),
                aggregator.getTimestamp(roundId)
            );
        } else {
            RateAndUpdatedTime memory update = _rates[currencyKey][roundId];
            return (_rateOrInverted(currencyKey, update.rate), update.time);
        }
    }

    function _getRate(bytes32 currencyKey) internal view returns (uint256) {
        return _getRateAndUpdatedTime(currencyKey).rate;
    }

    function _getUpdatedTime(bytes32 currencyKey) internal view returns (uint256) {
        return _getRateAndUpdatedTime(currencyKey).time;
    }

    function _effectiveValueAndRates(
        bytes32 sourceCurrencyKey,
        uint sourceAmount,
        bytes32 destinationCurrencyKey
    )
        internal
        view
        returns (
            uint value,
            uint sourceRate,
            uint destinationRate
        )
    {
        sourceRate = _getRate(sourceCurrencyKey);
        // If there's no change in the currency, then just return the amount they gave us
        if (sourceCurrencyKey == destinationCurrencyKey) {
            destinationRate = sourceRate;
            value = sourceAmount;
        } else {
            // Calculate the effective value by going from source -> USD -> destination
            destinationRate = _getRate(destinationCurrencyKey);
            value = sourceAmount.multiplyDecimalRound(sourceRate).divideDecimalRound(destinationRate);
        }
    }

    function _rateIsStale(bytes32 currencyKey, uint _rateStalePeriod) internal view returns (bool) {
        // sUSD is a special case and is never stale (check before an SLOAD of getRateAndUpdatedTime)
        if (currencyKey == "sUSD") return false;

        return _rateIsStaleWithTime(_rateStalePeriod, _getUpdatedTime(currencyKey));
    }

    function _rateIsStaleWithTime(uint _rateStalePeriod, uint _time) internal view returns (bool) {
        return _time.add(_rateStalePeriod) < now;
    }

    function _rateIsFrozen(bytes32 currencyKey) internal view returns (bool) {
        InversePricing memory inverse = inversePricing[currencyKey];
        return inverse.frozenAtUpperLimit || inverse.frozenAtLowerLimit;
    }

    function _rateIsFlagged(bytes32 currencyKey, FlagsInterface flags) internal view returns (bool) {
        // sUSD is a special case and is never invalid
        if (currencyKey == "sUSD") return false;
        address aggregator = address(aggregators[currencyKey]);
        // when no aggregator or when the flags haven't been setup
        if (aggregator == address(0) || flags == FlagsInterface(0)) {
            return false;
        }
        return flags.getFlag(aggregator);
    }

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

    modifier onlyOracle {
        require(msg.sender == oracle, "Only the oracle can perform this action");
        _;
    }

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

    event OracleUpdated(address newOracle);
    event RatesUpdated(bytes32[] currencyKeys, uint[] newRates);
    event RateDeleted(bytes32 currencyKey);
    event InversePriceConfigured(bytes32 currencyKey, uint entryPoint, uint upperLimit, uint lowerLimit);
    event InversePriceFrozen(bytes32 currencyKey, uint rate, address initiator);
    event AggregatorAdded(bytes32 currencyKey, address aggregator);
    event AggregatorRemoved(bytes32 currencyKey, address aggregator);
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_resolver","type":"address"},{"internalType":"bytes32[]","name":"_currencyKeys","type":"bytes32[]"},{"internalType":"uint256[]","name":"_newRates","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"aggregator","type":"address"}],"name":"AggregatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"aggregator","type":"address"}],"name":"AggregatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"entryPoint","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"upperLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lowerLimit","type":"uint256"}],"name":"InversePriceConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"},{"indexed":false,"internalType":"address","name":"initiator","type":"address"}],"name":"InversePriceFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOracle","type":"address"}],"name":"OracleUpdated","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"}],"name":"RateDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"},{"indexed":false,"internalType":"uint256[]","name":"newRates","type":"uint256[]"}],"name":"RatesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newBeneficiary","type":"address"}],"name":"SelfDestructBeneficiaryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"selfDestructDelay","type":"uint256"}],"name":"SelfDestructInitiated","type":"event"},{"anonymous":false,"inputs":[],"name":"SelfDestructTerminated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"}],"name":"SelfDestructed","type":"event"},{"constant":true,"inputs":[],"name":"MAX_ADDRESSES_FROM_RESOLVER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SELFDESTRUCT_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"aggregatorAddress","type":"address"}],"name":"addAggregator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"aggregatorKeys","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"aggregatorWarningFlags","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"aggregators","outputs":[{"internalType":"contract AggregatorInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"anyRateIsInvalid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"canFreezeRate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"aggregator","type":"address"}],"name":"currenciesUsingAggregator","outputs":[{"internalType":"bytes32[]","name":"currencies","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"currentRoundForRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"deleteRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"effectiveValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"effectiveValueAndRates","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"sourceRate","type":"uint256"},{"internalType":"uint256","name":"destinationRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"roundIdForSrc","type":"uint256"},{"internalType":"uint256","name":"roundIdForDest","type":"uint256"}],"name":"effectiveValueAtRound","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"freezeRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"getCurrentRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"internalType":"uint256","name":"startingTimestamp","type":"uint256"},{"internalType":"uint256","name":"timediff","type":"uint256"}],"name":"getLastRoundIdBeforeElapsedSecs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getResolverAddressesRequired","outputs":[{"internalType":"bytes32[24]","name":"addressesRequired","type":"bytes32[24]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"initiateSelfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initiationTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"inversePricing","outputs":[{"internalType":"uint256","name":"entryPoint","type":"uint256"},{"internalType":"uint256","name":"upperLimit","type":"uint256"},{"internalType":"uint256","name":"lowerLimit","type":"uint256"},{"internalType":"bool","name":"frozenAtUpperLimit","type":"bool"},{"internalType":"bool","name":"frozenAtLowerLimit","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"invertedKeys","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract AddressResolver","name":"_resolver","type":"address"}],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"lastRateUpdateTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"lastRateUpdateTimesForCurrencies","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":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"rateAndTimestampAtRound","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateAndUpdatedTime","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateForCurrency","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateIsFlagged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateIsFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateIsInvalid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateIsStale","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"rateStalePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"ratesAndInvalidForCurrencies","outputs":[{"internalType":"uint256[]","name":"rates","type":"uint256[]"},{"internalType":"bool","name":"anyRateInvalid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"numRounds","type":"uint256"}],"name":"ratesAndUpdatedTimeForCurrencyLastNRounds","outputs":[{"internalType":"uint256[]","name":"rates","type":"uint256[]"},{"internalType":"uint256[]","name":"times","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"ratesForCurrencies","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"removeAggregator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"removeInversePricing","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"selfDestructBeneficiary","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"selfDestructInitiated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"entryPoint","type":"uint256"},{"internalType":"uint256","name":"upperLimit","type":"uint256"},{"internalType":"uint256","name":"lowerLimit","type":"uint256"},{"internalType":"bool","name":"freezeAtUpperLimit","type":"bool"},{"internalType":"bool","name":"freezeAtLowerLimit","type":"bool"}],"name":"setInversePricing","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract AddressResolver","name":"_resolver","type":"address"}],"name":"setResolverAndSyncCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_beneficiary","type":"address"}],"name":"setSelfDestructBeneficiary","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"terminateSelfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"},{"internalType":"uint256[]","name":"newRates","type":"uint256[]"},{"internalType":"uint256","name":"timeSent","type":"uint256"}],"name":"updateRates","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

60a06040526822bc31b430b733b2b960b91b60809081526200002690600e90600162000d59565b503480156200003457600080fd5b506040516200530e3803806200530e833981810160405260a08110156200005a57600080fd5b8151602083015160408085015160608601805192519496939591949391820192846401000000008211156200008e57600080fd5b908301906020820185811115620000a457600080fd5b8251866020820283011164010000000082111715620000c257600080fd5b82525081516020918201928201910280838360005b83811015620000f1578181015183820152602001620000d7565b50505050905001604052602001805160405193929190846401000000008211156200011b57600080fd5b9083019060208201858111156200013157600080fd5b82518660208202830111640100000000821117156200014f57600080fd5b82525081516020918201928201910280838360005b838110156200017e57818101518382015260200162000164565b5050505090910161030081016040819052889550909350600e92506018915082845b815481526020019060010190808311620001a057508a93505050506001600160a01b03811662000217576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1506000546001600160a01b0316620002c2576040805162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b604482015290519081900360640190fd5b60005460038054610100600160a81b0319166101006001600160a01b0390931692830217905560408051918252517fd5da63a0b864b315bc04128dedbc93888c8529ee6cf47ce664dc204339228c53916020908290030190a16000546001600160a01b03166200036d576040805162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b604482015290519081900360640190fd5b60005b6018811015620003d55760008282601881106200038957fe5b602002015114620003c6576006828260188110620003a357fe5b6020908102919091015182546001810184556000938452919092200155620003cc565b620003d5565b60010162000370565b5050600480546001600160a01b0319166001600160a01b0392909216919091179055620004146e466c657869626c6553746f7261676560881b6200052e565b8051825114620004565760405162461bcd60e51b815260040180806020018281038252602f8152602001806200521c602f913960400191505060405180910390fd5b83600860006101000a8154816001600160a01b0302191690836001600160a01b031602179055506200050c631cd554d160e21b7334a5ef81d18f3a305ae9c2d7df42beef4c79031c63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015620004ce57600080fd5b505af4158015620004e3573d6000803e3d6000fd5b505050506040513d6020811015620004fa57600080fd5b5051426001600160e01b036200065f16565b620005228282426001600160e01b03620006d816565b50505050505062000e06565b6006805460018101825560008290527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0182905554601811620005b8576040805162461bcd60e51b815260206004820152601b60248201527f4d6178207265736f6c7665722063616368652073697a65206d65740000000000604482015290519081900360640190fd5b60048054604080516321f8a72160e01b8152928301849052516001600160a01b03909116916321f8a721916024808301926020929190829003018186803b1580156200060357600080fd5b505afa15801562000618573d6000803e3d6000fd5b505050506040513d60208110156200062f57600080fd5b505160009182526005602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b6000838152600d60209081526040808320805460010190819055815180830183526001600160d81b03968716815264ffffffffff958616818501908152978552600784528285209185529252909120905181549451909216600160d81b029183166001600160d81b031990941693909317909116179055565b600082518451146200071c5760405162461bcd60e51b81526004018080602001828103825260388152602001806200529d6038913960400191505060405180910390fd5b6102584201821062000775576040805162461bcd60e51b815260206004820152601f60248201527f54696d6520697320746f6f2066617220696e746f207468652066757475726500604482015290519081900360640190fd5b60005b84518110156200088e5760008582815181106200079157fe5b60200260200101519050848281518110620007a857fe5b602002602001015160001415620007f15760405162461bcd60e51b8152600401808060200182810382526039815260200180620052d56039913960400191505060405180910390fd5b80631cd554d160e21b1415620008395760405162461bcd60e51b81526004018080602001828103825260318152602001806200524b6031913960400191505060405180910390fd5b6200084d816001600160e01b036200095816565b8410156200085c575062000885565b62000883818684815181106200086e57fe5b6020026020010151866200065f60201b60201c565b505b60010162000778565b507f1bc0fc8997efa076f59b5ef02c315bc5390f7a6d24d661ce12128c01a3b0ba578484604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015620008f8578181015183820152602001620008de565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015620009395781810151838201526020016200091f565b5050505090500194505050505060405180910390a15060019392505050565b60006200096e826001600160e01b036200098116565b6020015164ffffffffff1690505b919050565b6200098b62000d9c565b6000828152600960205260409020546001600160a01b0316801562000ac157604051806040016040528062000a38856402540be400856001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015620009fa57600080fd5b505afa15801562000a0f573d6000803e3d6000fd5b505050506040513d602081101562000a2657600080fd5b5051026001600160e01b0362000b5d16565b6001600160d81b03168152602001826001600160a01b0316638205bf6a6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000a8057600080fd5b505afa15801562000a95573d6000803e3d6000fd5b505050506040513d602081101562000aac57600080fd5b505164ffffffffff16905291506200097c9050565b62000acb62000d9c565b506000838152600760209081526040808320600d83528184205484528252918290208251808401845290546001600160d81b038082168352600160d81b90910464ffffffffff169282019290925282518084019093528051909291829162000b369188911662000b5d565b6001600160d81b03168152602001826020015164ffffffffff16815250925050506200097c565b600062000b6962000db3565b506000838152600b6020908152604091829020825160a08101845281548082526001830154938201939093526002820154938101939093526003015460ff808216151560608501526101009091041615156080830152158062000bca575082155b1562000bda578291505062000c90565b82915080606001511562000bf5578060200151915062000c8e565b80608001511562000c0d578060400151915062000c8e565b600062000c2e6002836000015162000c9660201b620039aa1790919060201c565b905083811162000c42576000925062000c5f565b62000c5c848262000cfb60201b6200409e1790919060201c565b92505b8160200151831062000c78578160200151925062000c8c565b8160400151831162000c8c57816040015192505b505b505b92915050565b60008262000ca75750600062000c90565b8282028284828162000cb557fe5b041462000cf45760405162461bcd60e51b81526004018080602001828103825260218152602001806200527c6021913960400191505060405180910390fd5b9392505050565b60008282111562000d53576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b826018810192821562000d8a579160200282015b8281111562000d8a57825182559160200191906001019062000d6d565b5062000d9892915062000de6565b5090565b604080518082019091526000808252602082015290565b6040518060a001604052806000815260200160008152602001600081526020016000151581526020016000151581525090565b62000e0391905b8082111562000d98576000815560010162000ded565b90565b6144068062000e166000396000f3fe608060405234801561001057600080fd5b50600436106103615760003560e01c80637103353e116101c8578063af3aea8611610104578063c6c9d828116100a2578063ce8480ea1161007c578063ce8480ea14610d08578063de02795e14610d25578063e3235c9114610d42578063fdadbc7e14610d4a57610361565b8063c6c9d82814610bff578063c8e5bbd514610c1c578063c8e6f39514610ceb57610361565b8063bd32aa44116100de578063bd32aa4414610abd578063bfa005ce14610ac5578063c2c8a67614610b87578063c58aaae614610bf757610361565b8063af3aea8614610a59578063b199c76414610a76578063b8225dec14610ab557610361565b80638295016a116101715780639cb8a26a1161014b5780639cb8a26a146109eb578063a461fc82146109f3578063ab49848c146109fb578063ac82f60814610a3c57610361565b80638295016a1461097f5780638da5cb5b146109c6578063935f4abd146109ce57610361565b80637a018a1e116101a25780637a018a1e146109275780637adbf973146109445780637dc0d1d01461097757610361565b80637103353e146108b6578063728dec29146108d357806379ba50971461091f57610361565b80632d7371e1116102a25780634308a94f116102405780634f72def61161021a5780634f72def61461083557806353a47bb714610852578063631e14441461085a578063654a60ac1461088d57610361565b80634308a94f146107da57806345938849146108105780634c36b8371461082d57610361565b80633375fcd11161027c5780633375fcd11461073457806338aa1b99146107515780633be99e6f1461076e5780633f0e084f146107a157610361565b80632d7371e1146106535780632ea913d41461070f5780633278c9601461072c57610361565b80631627540c1161030f5780632528f0fe116102e95780632528f0fe146105b1578063266da16b146105ce5780632678df96146106035780632bed9e0c1461063657610361565b80631627540c1461054157806317c70de41461057657806320714f881461057e57610361565b80630a7d36d1116103405780630a7d36d1146104885780630ee4951b146104f8578063109e46a21461051257610361565b80629919c01461036657806304f3bcec1461039757806305a046e5146103c8575b600080fd5b6103836004803603602081101561037c57600080fd5b5035610d6d565b604080519115158252519081900360200190f35b61039f610d88565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b610438600480360360208110156103de57600080fd5b8101906020810181356401000000008111156103f957600080fd5b82018360208201111561040b57600080fd5b8035906020019184602083028401116401000000008311171561042d57600080fd5b509092509050610da4565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561047457818101518382015260200161045c565b505050509050019250505060405180910390f35b6103836004803603602081101561049e57600080fd5b8101906020810181356401000000008111156104b957600080fd5b8201836020820111156104cb57600080fd5b803590602001918460208302840111640100000000831117156104ed57600080fd5b509092509050610e26565b610500610ed9565b60408051918252519081900360200190f35b6105006004803603608081101561052857600080fd5b5080359060208101359060408101359060600135610ee9565b6105746004803603602081101561055757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610f2c565b005b610500610ffb565b6105746004803603602081101561059457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611001565b610383600480360360208110156105c757600080fd5b503561113f565b610500600480360360a08110156105e457600080fd5b5080359060208101359060408101359060608101359060800135611164565b6104386004803603602081101561061957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166111c1565b6105746004803603602081101561064c57600080fd5b5035611282565b6106766004803603604081101561066957600080fd5b50803590602001356113ec565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156106ba5781810151838201526020016106a2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156106f95781810151838201526020016106e1565b5050505090500194505050505060405180910390f35b6105006004803603602081101561072557600080fd5b50356114dd565b6105746114fb565b6103836004803603602081101561074a57600080fd5b50356115a9565b6103836004803603602081101561076757600080fd5b503561166f565b6105746004803603602081101561078457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661167d565b610574600480360360408110156107b757600080fd5b508035906020013573ffffffffffffffffffffffffffffffffffffffff16611865565b6107f7600480360360208110156107f057600080fd5b5035611a74565b6040805192835260208301919091528051918290030190f35b6105746004803603602081101561082657600080fd5b5035611ac0565b61039f611bfb565b6105006004803603602081101561084b57600080fd5b5035611c05565b61039f611c12565b6103836004803603602081101561087057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611c2e565b610500600480360360608110156108a357600080fd5b5080359060208101359060400135611d97565b61039f600480360360208110156108cc57600080fd5b5035611daf565b6108f0600480360360208110156108e957600080fd5b5035611dd7565b604080519586526020860194909452848401929092521515606084015215156080830152519081900360a00190f35b610574611e0a565b6105006004803603602081101561093d57600080fd5b5035611f05565b6105746004803603602081101561095a57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611f10565b61039f611fe5565b6109a86004803603606081101561099557600080fd5b5080359060208101359060400135612001565b60408051938452602084019290925282820152519081900360600190f35b61039f612021565b610500600480360360208110156109e457600080fd5b503561203d565b61057461204f565b6105006121c8565b610a036121cf565b604051808261030080838360005b83811015610a29578181015183820152602001610a11565b5050505090500191505060405180910390f35b61050060048036036020811015610a5257600080fd5b5035612219565b61038360048036036020811015610a6f57600080fd5b5035612248565b610574600480360360c0811015610a8c57600080fd5b50803590602081013590604081013590606081013590608081013515159060a001351515612253565b610383612641565b61057461264a565b61038360048036036060811015610adb57600080fd5b810190602081018135640100000000811115610af657600080fd5b820183602082011115610b0857600080fd5b80359060200191846020830284011164010000000083111715610b2a57600080fd5b919390929091602081019035640100000000811115610b4857600080fd5b820183602082011115610b5a57600080fd5b80359060200191846020830284011164010000000083111715610b7c57600080fd5b919350915035612707565b61043860048036036020811015610b9d57600080fd5b810190602081018135640100000000811115610bb857600080fd5b820183602082011115610bca57600080fd5b80359060200191846020830284011164010000000083111715610bec57600080fd5b5090925090506127d9565b61039f612851565b61050060048036036020811015610c1557600080fd5b5035612872565b610c8c60048036036020811015610c3257600080fd5b810190602081018135640100000000811115610c4d57600080fd5b820183602082011115610c5f57600080fd5b80359060200191846020830284011164010000000083111715610c8157600080fd5b50909250905061287f565b604051808060200183151515158152602001828103825284818151815260200191508051906020019060200280838360005b83811015610cd6578181015183820152602001610cbe565b50505050905001935050505060405180910390f35b61057460048036036020811015610d0157600080fd5b50356129f3565b61050060048036036020811015610d1e57600080fd5b5035612b4f565b61057460048036036020811015610d3b57600080fd5b5035612b5a565b610500612d59565b6107f760048036036040811015610d6057600080fd5b5080359060200135612d5e565b6000610d8082610d7b612d76565b612e49565b90505b919050565b60045473ffffffffffffffffffffffffffffffffffffffff1681565b60608083839050604051908082528060200260200182016040528015610dd4578160200160208202803883390190505b50905060005b83811015610e1c57610dfd858583818110610df157fe5b90506020020135612e94565b828281518110610e0957fe5b6020908102919091010152600101610dda565b5090505b92915050565b600080610e31612d76565b90506060610e71858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612eb092505050565b905060005b84811015610ecd57818181518110610e8a57fe5b602002602001015180610eb45750610eb4868683818110610ea757fe5b9050602002013584612e49565b15610ec55760019350505050610e20565b600101610e76565b50600095945050505050565b6000610ee3612d76565b90505b90565b600083815b610efb878360010161315e565b915050801580610f0c575083850181115b15610f1957509050610f24565b600190910190610eee565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f825760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b60025481565b60005473ffffffffffffffffffffffffffffffffffffffff1633146110575760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166110bf576040805162461bcd60e51b815260206004820152601c60248201527f42656e6566696369617279206d757374206e6f74206265207a65726f00000000604482015290519081900360640190fd5b6003805473ffffffffffffffffffffffffffffffffffffffff831661010081027fffffffffffffffffffffff0000000000000000000000000000000000000000ff9092169190911790915560408051918252517fd5da63a0b864b315bc04128dedbc93888c8529ee6cf47ce664dc204339228c539181900360200190a150565b600061114d82610d7b612d76565b80610d805750610d808261115f613340565b6133e2565b6000838614156111755750836111b8565b6000611181878561315e565b5090506000611190868561315e565b5090506111b3816111a7898563ffffffff61351a16565b9063ffffffff61352f16565b925050505b95945050505050565b600a546040805182815260208084028201019091526060916000919080156111f3578160200160208202803883390190505b50915060005b600a5481101561127b576000600a828154811061121257fe5b6000918252602080832090910154808352600990915260409091205490915073ffffffffffffffffffffffffffffffffffffffff9081169086161415611272578084848060010195508151811061126557fe5b6020026020010181815250505b506001016111f9565b5050919050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146112d85760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b60008181526009602052604090205473ffffffffffffffffffffffffffffffffffffffff168061134f576040805162461bcd60e51b815260206004820152601c60248201527f4e6f2061676772656761746f722065786973747320666f72206b657900000000604482015290519081900360640190fd5b600082815260096020526040812080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561138e83600a613544565b905080156113e7576040805184815273ffffffffffffffffffffffffffffffffffffffff8416602082015281517fec70e890fc7db7de4059b114c9093a1f41283d18ffcfbcac45566feea4d4f777929181900390910190a15b505050565b60608082604051908082528060200260200182016040528015611419578160200160208202803883390190505b50915082604051908082528060200260200182016040528015611446578160200160208202803883390190505b509050600061145485613624565b905060005b848110156114d35761146b868361315e565b85838151811061147757fe5b6020026020010185848151811061148a57fe5b602090810291909101019190915252816114a657506114d69050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90910190600101611459565b50505b9250929050565b600c81815481106114ea57fe5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146115515760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b60006002819055600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517f6adcc7125002935e0aa31697538ebbd65cfddf20431eb6ecdcfc3e238bfd082c9190a1565b60006115b3614165565b506000828152600b6020908152604091829020825160a08101845281548082526001830154938201939093526002820154938101939093526003015460ff8082161515606085015261010090910416151560808301521580611616575080606001515b80611622575080608001515b15611631576000915050610d83565b600061163c84612219565b90506000811180156116605750816020015181101580611660575081604001518111155b92505050610d83565b50919050565b6000610d808261115f613340565b60005473ffffffffffffffffffffffffffffffffffffffff1633146116d35760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831617905560005b6006548110156118615760006006828154811061172f57fe5b6000918252602091829020015460048054604080517fdacb2d0100000000000000000000000000000000000000000000000000000000815292830184905260248301819052601760448401527f5265736f6c766572206d697373696e672074617267657400000000000000000060648401525192945073ffffffffffffffffffffffffffffffffffffffff169263dacb2d0192608480840193829003018186803b1580156117dc57600080fd5b505afa1580156117f0573d6000803e3d6000fd5b505050506040513d602081101561180657600080fd5b505160009182526005602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055600101611716565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146118bb5760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b600081905060008173ffffffffffffffffffffffffffffffffffffffff16638205bf6a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561190857600080fd5b505afa15801561191c573d6000803e3d6000fd5b505050506040513d602081101561193257600080fd5b50511015611987576040805162461bcd60e51b815260206004820152601b60248201527f476976656e2041676772656761746f7220697320696e76616c69640000000000604482015290519081900360640190fd5b60008381526009602052604090205473ffffffffffffffffffffffffffffffffffffffff166119e657600a80546001810182556000919091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8018390555b60008381526009602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915582518681529182015281517f0bcae573430f69c5361e5d76534d3f61d2d803958778680cd74be9dc6299bc63929181900390910190a1505050565b600080611a7f614198565b611a88846136e0565b80516020909101517affffffffffffffffffffffffffffffffffffffffffffffffffffff909116935064ffffffffff16915050915091565b60085473ffffffffffffffffffffffffffffffffffffffff163314611b165760405162461bcd60e51b815260040180806020018281038252602781526020018061426e6027913960400191505060405180910390fd5b6000611b2182612219565b11611b73576040805162461bcd60e51b815260206004820152600c60248201527f52617465206973207a65726f0000000000000000000000000000000000000000604482015290519081900360640190fd5b6000818152600760209081526040808320600d808452828520805486529184528285208590559385905292825282547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01909255815183815291517fe69d655565c7ff1353d8eaeea62fb7904fa9696987431ec351be288c865f1ae19281900390910190a150565b6000610ee3613340565b600a81815481106114ea57fe5b60015473ffffffffffffffffffffffffffffffffffffffff1681565b60045460009073ffffffffffffffffffffffffffffffffffffffff838116911614611c5b57506000610d83565b60005b600654811015611d8e57600060068281548110611c7757fe5b600091825260208083209091015480835260058252604092839020546004805485517f21f8a721000000000000000000000000000000000000000000000000000000008152918201849052945192955073ffffffffffffffffffffffffffffffffffffffff91821694909116926321f8a72192602480840193829003018186803b158015611d0457600080fd5b505afa158015611d18573d6000803e3d6000fd5b505050506040513d6020811015611d2e57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff16141580611d75575060008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff16155b15611d8557600092505050610d83565b50600101611c5e565b50600192915050565b6000611da48484846138eb565b509095945050505050565b60096020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600b6020526000908152604090208054600182015460028301546003909301549192909160ff8082169161010090041685565b60015473ffffffffffffffffffffffffffffffffffffffff163314611e605760405162461bcd60e51b81526004018080602001828103825260358152602001806142086035913960400191505060405180910390fd5b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6000610d8082613624565b60005473ffffffffffffffffffffffffffffffffffffffff163314611f665760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116919091179182905560408051929091168252517f3df77beb5db05fcdd70a30fc8adf3f83f9501b68579455adbd100b8180940394916020908290030190a150565b60085473ffffffffffffffffffffffffffffffffffffffff1681565b60008060006120118686866138eb565b9250925092505b93509350939050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600d6020526000908152604090205481565b60005473ffffffffffffffffffffffffffffffffffffffff1633146120a55760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b60035460ff166120fc576040805162461bcd60e51b815260206004820152601f60248201527f53656c66204465737472756374206e6f742079657420696e6974696174656400604482015290519081900360640190fd5b426224ea006002540110612157576040805162461bcd60e51b815260206004820152601b60248201527f53656c662064657374727563742064656c6179206e6f74206d65740000000000604482015290519081900360640190fd5b6003546040805161010090920473ffffffffffffffffffffffffffffffffffffffff168252517f8a09e1677ced846cb537dc2b172043bd05a1a81ad7e0033a7ef8ba762df990b7916020908290030190a1600354610100900473ffffffffffffffffffffffffffffffffffffffff16ff5b6224ea0081565b6121d76141af565b60005b60065481101561221557600681815481106121f157fe5b906000526020600020015482826018811061220857fe5b60200201526001016121da565b5090565b6000612224826136e0565b517affffffffffffffffffffffffffffffffffffffffffffffffffffff1692915050565b6000610d8082613937565b60005473ffffffffffffffffffffffffffffffffffffffff1633146122a95760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b600083116122fe576040805162461bcd60e51b815260206004820152601a60248201527f6c6f7765724c696d6974206d7573742062652061626f76652030000000000000604482015290519081900360640190fd5b84841161233c5760405162461bcd60e51b81526004018080602001828103825260278152602001806143ab6027913960400191505060405180910390fd5b61234d85600263ffffffff6139aa16565b841061238a5760405162461bcd60e51b815260040180806020018281038252602e815260200180614344602e913960400191505060405180910390fd5b8483106123c85760405162461bcd60e51b815260040180806020018281038252602781526020018061431d6027913960400191505060405180910390fd5b8180156123d25750805b15612424576040805162461bcd60e51b815260206004820152601c60248201527f43616e6e6f7420667265657a6520617420626f7468206c696d69747300000000604482015290519081900360640190fd5b6000868152600b60205260409020805461246e57600c80546001810182556000919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7018790555b858155600181018590556002810184905582806124885750815b15612537576003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016841515177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100841515021790557f3de98bb945f5841b9e27e10a317b59497fa7aab6bc7ba00461fbb3211b55016587846125125785612514565b865b6040805192835260208301919091523382820152519081900360600190a1612562565b6003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555b600061256d88612219565b905080156125f05761257d613a03565b73ffffffffffffffffffffffffffffffffffffffff1663ce09694089836040518363ffffffff1660e01b81526004018083815260200182815260200192505050600060405180830381600087803b1580156125d757600080fd5b505af11580156125eb573d6000803e3d6000fd5b505050505b60408051898152602081018990528082018890526060810187905290517f37efb38e92b0f94698f6df0c9070e2f00946862a042ac09e34ae8c547684240a9181900360800190a15050505050505050565b60035460ff1681565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126a05760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b42600255600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055604080516224ea00815290517fcbd94ca75b8dc45c9d80c77e851670e78843c0d75180cb81db3e2158228fa9a69181900360200190a1565b60085460009073ffffffffffffffffffffffffffffffffffffffff1633146127605760405162461bcd60e51b815260040180806020018281038252602781526020018061426e6027913960400191505060405180910390fd5b6127cf86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250879250613a64915050565b9695505050505050565b60608083839050604051908082528060200260200182016040528015612809578160200160208202803883390190505b50905060005b83811015610e1c5761283285858381811061282657fe5b90506020020135612219565b82828151811061283e57fe5b602090810291909101015260010161280f565b600354610100900473ffffffffffffffffffffffffffffffffffffffff1681565b600681815481106114ea57fe5b60606000838390506040519080825280602002602001820160405280156128b0578160200160208202803883390190505b50915060006128bd612d76565b905060606128fd868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612eb092505050565b905060005b858110156129e957612912614198565b61292d88888481811061292157fe5b905060200201356136e0565b905080600001517affffffffffffffffffffffffffffffffffffffffffffffffffffff1686838151811061295d57fe5b602002602001018181525050841580156129a9575087878381811061297e57fe5b905060200201357f735553440000000000000000000000000000000000000000000000000000000014155b156129e0578282815181106129ba57fe5b6020026020010151806129dd57506129dd84826020015164ffffffffff16613cd8565b94505b50600101612902565b5050509250929050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612a495760405162461bcd60e51b815260040180806020018281038252602f815260200180614295602f913960400191505060405180910390fd5b6000818152600b6020526040902054612aa9576040805162461bcd60e51b815260206004820152601860248201527f4e6f20696e766572746564207072696365206578697374730000000000000000604482015290519081900360640190fd5b6000818152600b60205260408120818155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055612afc82600c613544565b905080156118615760408051838152600060208201819052818301819052606082015290517f37efb38e92b0f94698f6df0c9070e2f00946862a042ac09e34ae8c547684240a9181900360800190a15050565b6000610d8082612e94565b6000818152600b602052604090208054612bbb576040805162461bcd60e51b815260206004820152601e60248201527f43616e6e6f7420667265657a65206e6f6e2d696e766572736520726174650000604482015290519081900360640190fd5b600381015460ff16158015612bda57506003810154610100900460ff16155b612c2b576040805162461bcd60e51b815260206004820152601a60248201527f546865207261746520697320616c72656164792066726f7a656e000000000000604482015290519081900360640190fd5b6000612c3683612219565b9050600081118015612c5a5750816001015481101580612c5a575081600201548111155b15612d0c57600182015460038301805460028501548414610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090921693851493909317169190911790556040805184815260208101839052338183015290517f3de98bb945f5841b9e27e10a317b59497fa7aab6bc7ba00461fbb3211b5501659181900360600190a16113e7565b6040805162461bcd60e51b815260206004820152601260248201527f526174652077697468696e20626f756e64730000000000000000000000000000604482015290519081900360640190fd5b601881565b600080612d6b848461315e565b915091509250929050565b6000612d80613cf3565b73ffffffffffffffffffffffffffffffffffffffff166323257c2b7f53797374656d53657474696e67730000000000000000000000000000000000007f726174655374616c65506572696f6400000000000000000000000000000000006040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015612e1857600080fd5b505afa158015612e2c573d6000803e3d6000fd5b505050506040513d6020811015612e4257600080fd5b5051905090565b6000827f73555344000000000000000000000000000000000000000000000000000000001415612e7b57506000610e20565b612e8d82612e8885612e94565b613cd8565b9392505050565b6000612e9f826136e0565b6020015164ffffffffff1692915050565b60606000612ebc613340565b905073ffffffffffffffffffffffffffffffffffffffff81161561312b5760608351604051908082528060200260200182016040528015612f07578160200160208202803883390190505b50905060005b8451811015612f965760096000868381518110612f2657fe5b6020026020010151815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828281518110612f6957fe5b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152600101612f0d565b506040517f7d723cac00000000000000000000000000000000000000000000000000000000815260206004820181815283516024840152835173ffffffffffffffffffffffffffffffffffffffff861693637d723cac93869392839260440191808601910280838360005b83811015613019578181015183820152602001613001565b505050509050019250505060006040518083038186803b15801561303c57600080fd5b505afa158015613050573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561309757600080fd5b81019080805160405193929190846401000000008211156130b757600080fd5b9083019060208201858111156130cc57600080fd5b82518660208202830111640100000000821117156130e957600080fd5b82525081516020918201928201910280838360005b838110156131165781810151838201526020016130fe565b50505050905001604052505050925050611669565b8251604051908082528060200260200182016040528015613156578160200160208202803883390190505b509392505050565b600082815260096020526040812054819073ffffffffffffffffffffffffffffffffffffffff1680156132a157613218856402540be4008373ffffffffffffffffffffffffffffffffffffffff1663b5ab58dc886040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156131e657600080fd5b505afa1580156131fa573d6000803e3d6000fd5b505050506040513d602081101561321057600080fd5b505102613d54565b8173ffffffffffffffffffffffffffffffffffffffff1663b633620c866040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561326957600080fd5b505afa15801561327d573d6000803e3d6000fd5b505050506040513d602081101561329357600080fd5b505190935091506114d69050565b6132a9614198565b5060008581526007602090815260408083208784528252918290208251808401909352547affffffffffffffffffffffffffffffffffffffffffffffffffffff81168084527b0100000000000000000000000000000000000000000000000000000090910464ffffffffff1691830191909152613327908790613d54565b60209091015190935064ffffffffff1691506114d69050565b600061334a613cf3565b73ffffffffffffffffffffffffffffffffffffffff16639ee5955a7f53797374656d53657474696e67730000000000000000000000000000000000007f61676772656761746f725761726e696e67466c616773000000000000000000006040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015612e1857600080fd5b6000827f7355534400000000000000000000000000000000000000000000000000000000141561341457506000610e20565b60008381526009602052604090205473ffffffffffffffffffffffffffffffffffffffff1680158061345a575073ffffffffffffffffffffffffffffffffffffffff8316155b15613469576000915050610e20565b8273ffffffffffffffffffffffffffffffffffffffff1663357e47fe826040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156134e657600080fd5b505afa1580156134fa573d6000803e3d6000fd5b505050506040513d602081101561351057600080fd5b5051949350505050565b6000612e8d8383670de0b6b3a7640000613e69565b6000612e8d8383670de0b6b3a7640000613ea6565b6000805b825481101561361a578383828154811061355e57fe5b906000526020600020015414156136125782818154811061357b57fe5b6000918252602082200155825483907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081106135b657fe5b90600052602060002001548382815481106135cd57fe5b6000918252602090912001558254613607847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83016141ce565b506001915050610e20565b600101613548565b5060009392505050565b60008181526009602052604081205473ffffffffffffffffffffffffffffffffffffffff1680156136ca578073ffffffffffffffffffffffffffffffffffffffff1663668a0f026040518163ffffffff1660e01b815260040160206040518083038186803b15801561369557600080fd5b505afa1580156136a9573d6000803e3d6000fd5b505050506040513d60208110156136bf57600080fd5b50519150610d839050565b50506000818152600d6020526040902054610d83565b6136e8614198565b60008281526009602052604090205473ffffffffffffffffffffffffffffffffffffffff16801561381457604051806040016040528061376e856402540be4008573ffffffffffffffffffffffffffffffffffffffff166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156131e657600080fd5b7affffffffffffffffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff16638205bf6a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156137d657600080fd5b505afa1580156137ea573d6000803e3d6000fd5b505050506040513d602081101561380057600080fd5b505164ffffffffff1690529150610d839050565b61381c614198565b506000838152600760209081526040808320600d83528184205484528252918290208251808401845290547affffffffffffffffffffffffffffffffffffffffffffffffffffff80821683527b0100000000000000000000000000000000000000000000000000000090910464ffffffffff16928201929092528251808401909352805190929182916138b191889116613d54565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff168152602001826020015164ffffffffff1681525092505050610d83565b60008060006138f986612219565b91508386141561390d575083915080612018565b61391684612219565b905061392c816111a7878563ffffffff61351a16565b925093509350939050565b6000613941614165565b506000828152600b6020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff808216151560608401819052610100909204161515608083015280612e8d57506080015192915050565b6000826139b957506000610e20565b828202828482816139c657fe5b0414612e8d5760405162461bcd60e51b81526004018080602001828103825260218152602001806142c46021913960400191505060405180910390fd5b6000610ee37f45786368616e67657200000000000000000000000000000000000000000000006040518060400160405280601981526020017f4d697373696e672045786368616e676572206164647265737300000000000000815250613ed8565b60008251845114613aa65760405162461bcd60e51b81526004018080602001828103825260388152602001806142e56038913960400191505060405180910390fd5b61025842018210613afe576040805162461bcd60e51b815260206004820152601f60248201527f54696d6520697320746f6f2066617220696e746f207468652066757475726500604482015290519081900360640190fd5b60005b8451811015613c12576000858281518110613b1857fe5b60200260200101519050848281518110613b2e57fe5b602002602001015160001415613b755760405162461bcd60e51b81526004018080602001828103825260398152602001806143726039913960400191505060405180910390fd5b807f73555344000000000000000000000000000000000000000000000000000000001415613bd45760405162461bcd60e51b815260040180806020018281038252603181526020018061423d6031913960400191505060405180910390fd5b613bdd81612e94565b841015613bea5750613c0a565b613c0881868481518110613bfa57fe5b602002602001015186613f87565b505b600101613b01565b507f1bc0fc8997efa076f59b5ef02c315bc5390f7a6d24d661ce12128c01a3b0ba578484604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015613c7a578181015183820152602001613c62565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015613cb9578181015183820152602001613ca1565b5050505090500194505050505060405180910390a15060019392505050565b600042613ceb838563ffffffff61404416565b109392505050565b6000610ee37f466c657869626c6553746f7261676500000000000000000000000000000000006040518060400160405280601f81526020017f4d697373696e6720466c657869626c6553746f72616765206164647265737300815250613ed8565b6000613d5e614165565b506000838152600b6020908152604091829020825160a08101845281548082526001830154938201939093526002820154938101939093526003015460ff8082161515606085015261010090910416151560808301521580613dbe575082155b15613dcc5782915050610e20565b829150806060015115613de55780602001519150613e62565b806080015115613dfb5780604001519150613e62565b8051600090613e1190600263ffffffff6139aa16565b9050838111613e235760009250613e36565b613e33818563ffffffff61409e16565b92505b81602001518310613e4d5781602001519250613e60565b81604001518311613e6057816040015192505b505b5092915050565b600080600a8304613e80868663ffffffff6139aa16565b81613e8757fe5b0490506005600a825b0610613e9a57600a015b600a9004949350505050565b600080613ecc84613ec087600a870263ffffffff6139aa16565b9063ffffffff6140fb16565b90506005600a82613e90565b60008281526005602052604081205473ffffffffffffffffffffffffffffffffffffffff168281610e1c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613f4c578181015183820152602001613f34565b50505050905090810190601f168015613f795780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6000838152600d60209081526040808320805460010190819055815180830183527affffffffffffffffffffffffffffffffffffffffffffffffffffff968716815264ffffffffff9586168185019081529785526007845282852091855292529091209051815494519092167b01000000000000000000000000000000000000000000000000000000029183167fffffffffff00000000000000000000000000000000000000000000000000000090941693909317909116179055565b600082820183811015612e8d576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000828211156140f5576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808211614151576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b600082848161415c57fe5b04949350505050565b6040518060a001604052806000815260200160008152602001600081526020016000151581526020016000151581525090565b604080518082019091526000808252602082015290565b6040518061030001604052806018906020820280388339509192915050565b8154818355818111156113e7576000838152602090206113e7918101908301610ee691905b8082111561221557600081556001016141f356fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e65727368697052617465206f6620735553442063616e6e6f7420626520757064617465642c206974277320616c7761797320554e49542e4f6e6c7920746865206f7261636c652063616e20706572666f726d207468697320616374696f6e4f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743757272656e6379206b6579206172726179206c656e677468206d757374206d61746368207261746573206172726179206c656e6774682e6c6f7765724c696d6974206d7573742062652062656c6f772074686520656e747279506f696e7475707065724c696d6974206d757374206265206c657373207468616e20646f75626c6520656e747279506f696e745a65726f206973206e6f7420612076616c696420726174652c20706c656173652063616c6c2064656c6574655261746520696e73746561642e75707065724c696d6974206d7573742062652061626f76652074686520656e747279506f696e74a265627a7a72315820aa7a1a95992daa5d903ba729c95404c144eb38df43ec67c2a7c5759c0abee07464736f6c6343000510003243757272656e6379206b6579206c656e67746820616e642072617465206c656e677468206d757374206d617463682e52617465206f6620735553442063616e6e6f7420626520757064617465642c206974277320616c7761797320554e49542e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743757272656e6379206b6579206172726179206c656e677468206d757374206d61746368207261746573206172726179206c656e6774682e5a65726f206973206e6f7420612076616c696420726174652c20706c656173652063616c6c2064656c6574655261746520696e73746561642e000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882000000000000000000000000ac1e8b385230970319906c03a1d8567e3996d1d5000000000000000000000000c6f404c96aa136b0ba11d40db17394f09b0f20f100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000001534e580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000064ae07b84f5343ab

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

000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882000000000000000000000000ac1e8b385230970319906c03a1d8567e3996d1d5000000000000000000000000c6f404c96aa136b0ba11d40db17394f09b0f20f100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000001534e580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000064ae07b84f5343ab

-----Decoded View---------------
Arg [0] : _owner (address): 0xb64ff7a4a33acdf48d97dab0d764afd0f6176882
Arg [1] : _oracle (address): 0xac1e8b385230970319906c03a1d8567e3996d1d5
Arg [2] : _resolver (address): 0xc6f404c96aa136b0ba11d40db17394f09b0f20f1
Arg [3] : _currencyKeys (bytes32[]): 0xSystem.Collections.Generic.List`1[System.Object]
Arg [4] : _newRates (uint256[]): 0xSystem.Collections.Generic.List`1[System.Object]

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000b64ff7a4a33acdf48d97dab0d764afd0f6176882
Arg [1] : 000000000000000000000000ac1e8b385230970319906c03a1d8567e3996d1d5
Arg [2] : 000000000000000000000000c6f404c96aa136b0ba11d40db17394f09b0f20f1
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [6] : 534e580000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [8] : 00000000000000000000000000000000000000000000000064ae07b84f5343ab


Library Used

SafeDecimalMath : 0x34a5ef81d18f3a305ae9c2d7df42beef4c79031c

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