Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Multi Chain
Multichain Addresses
2 addresses found via
Latest 8 from a total of 8 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Settle | 17410099 | 182 days 12 hrs ago | IN | 0 ETH | 0.008517 | ||||
Settle | 16291178 | 339 days 19 hrs ago | IN | 0 ETH | 0.0023228 | ||||
Settle | 16189472 | 354 days 16 mins ago | IN | 0 ETH | 0.0137596 | ||||
Settle | 16179429 | 355 days 9 hrs ago | IN | 0 ETH | 0.02720244 | ||||
Settle | 15983329 | 382 days 19 hrs ago | IN | 0 ETH | 0.00507048 | ||||
Settle | 15891652 | 395 days 14 hrs ago | IN | 0 ETH | 0.00169346 | ||||
Nominate New Own... | 15890575 | 395 days 18 hrs ago | IN | 0 ETH | 0.00201613 | ||||
0x60806040 | 15890440 | 395 days 19 hrs ago | IN | Create: ExchangerWithFeeRecAlternatives | 0 ETH | 0.12963652 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ExchangerWithFeeRecAlternatives
Compiler Version
v0.5.16+commit.9c3226ce
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2022-11-03 */ /* ____ __ __ __ _ / __/__ __ ___ / /_ / / ___ / /_ (_)__ __ _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ / /___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\ /___/ * Synthetix: ExchangerWithFeeRecAlternatives.sol * * Latest source (may be newer): https://github.com/Synthetixio/synthetix/blob/master/contracts/ExchangerWithFeeRecAlternatives.sol * Docs: https://docs.synthetix.io/contracts/ExchangerWithFeeRecAlternatives * * Contract Dependencies: * - Exchanger * - IAddressResolver * - IExchanger * - MinimalProxyFactory * - MixinResolver * - MixinSystemSettings * - Owned * Libraries: * - ExchangeSettlementLib * - SafeDecimalMath * - SafeMath * * MIT License * =========== * * Copyright (c) 2022 Synthetix * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ pragma solidity ^0.5.16; // https://docs.synthetix.io/contracts/source/contracts/owned contract Owned { address public owner; address public nominatedOwner; constructor(address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { _onlyOwner(); _; } function _onlyOwner() private view { require(msg.sender == owner, "Only the contract owner may perform this action"); } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // https://docs.synthetix.io/contracts/source/interfaces/iaddressresolver interface IAddressResolver { function getAddress(bytes32 name) external view returns (address); function getSynth(bytes32 key) external view returns (address); function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address); } // https://docs.synthetix.io/contracts/source/interfaces/isynth interface ISynth { // Views function currencyKey() external view returns (bytes32); function transferableSynths(address account) external view returns (uint); // Mutative functions function transferAndSettle(address to, uint value) external returns (bool); function transferFromAndSettle( address from, address to, uint value ) external returns (bool); // Restricted: used internally to Synthetix function burn(address account, uint amount) external; function issue(address account, uint amount) external; } // https://docs.synthetix.io/contracts/source/interfaces/iissuer interface IIssuer { // Views function allNetworksDebtInfo() external view returns ( uint256 debt, uint256 sharesSupply, bool isStale ); function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid); function availableCurrencyKeys() external view returns (bytes32[] memory); function availableSynthCount() external view returns (uint); function availableSynths(uint index) external view returns (ISynth); function canBurnSynths(address account) external view returns (bool); function collateral(address account) external view returns (uint); function collateralisationRatio(address issuer) external view returns (uint); function collateralisationRatioAndAnyRatesInvalid(address _issuer) external view returns (uint cratio, bool anyRateIsInvalid); function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint debtBalance); function issuanceRatio() external view returns (uint); function lastIssueEvent(address account) external view returns (uint); function maxIssuableSynths(address issuer) external view returns (uint maxIssuable); function minimumStakeTime() external view returns (uint); function remainingIssuableSynths(address issuer) external view returns ( uint maxIssuable, uint alreadyIssued, uint totalSystemDebt ); function synths(bytes32 currencyKey) external view returns (ISynth); function getSynths(bytes32[] calldata currencyKeys) external view returns (ISynth[] memory); function synthsByAddress(address synthAddress) external view returns (bytes32); function totalIssuedSynths(bytes32 currencyKey, bool excludeOtherCollateral) external view returns (uint); function transferableSynthetixAndAnyRateIsInvalid(address account, uint balance) external view returns (uint transferable, bool anyRateIsInvalid); function liquidationAmounts(address account, bool isSelfLiquidation) external view returns ( uint totalRedeemed, uint debtToRemove, uint escrowToLiquidate, uint initialDebtBalance ); // Restricted: used internally to Synthetix function addSynths(ISynth[] calldata synthsToAdd) external; function issueSynths(address from, uint amount) external; function issueSynthsOnBehalf( address issueFor, address from, uint amount ) external; function issueMaxSynths(address from) external; function issueMaxSynthsOnBehalf(address issueFor, address from) external; function burnSynths(address from, uint amount) external; function burnSynthsOnBehalf( address burnForAddress, address from, uint amount ) external; function burnSynthsToTarget(address from) external; function burnSynthsToTargetOnBehalf(address burnForAddress, address from) external; function burnForRedemption( address deprecatedSynthProxy, address account, uint balance ) external; function setCurrentPeriodId(uint128 periodId) external; function liquidateAccount(address account, bool isSelfLiquidation) external returns ( uint totalRedeemed, uint debtRemoved, uint escrowToLiquidate ); function issueSynthsWithoutDebt( bytes32 currencyKey, address to, uint amount ) external returns (bool rateInvalid); function burnSynthsWithoutDebt( bytes32 currencyKey, address to, uint amount ) external returns (bool rateInvalid); } // Inheritance // Internal references // https://docs.synthetix.io/contracts/source/contracts/addressresolver contract AddressResolver is Owned, IAddressResolver { mapping(bytes32 => address) public repository; constructor(address _owner) public Owned(_owner) {} /* ========== RESTRICTED FUNCTIONS ========== */ function importAddresses(bytes32[] calldata names, address[] calldata destinations) external onlyOwner { require(names.length == destinations.length, "Input lengths must match"); for (uint i = 0; i < names.length; i++) { bytes32 name = names[i]; address destination = destinations[i]; repository[name] = destination; emit AddressImported(name, destination); } } /* ========= PUBLIC FUNCTIONS ========== */ function rebuildCaches(MixinResolver[] calldata destinations) external { for (uint i = 0; i < destinations.length; i++) { destinations[i].rebuildCache(); } } /* ========== VIEWS ========== */ function areAddressesImported(bytes32[] calldata names, address[] calldata destinations) external view returns (bool) { for (uint i = 0; i < names.length; i++) { if (repository[names[i]] != destinations[i]) { return false; } } return true; } function getAddress(bytes32 name) external view returns (address) { return repository[name]; } function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address) { address _foundAddress = repository[name]; require(_foundAddress != address(0), reason); return _foundAddress; } function getSynth(bytes32 key) external view returns (address) { IIssuer issuer = IIssuer(repository["Issuer"]); require(address(issuer) != address(0), "Cannot find Issuer address"); return address(issuer.synths(key)); } /* ========== EVENTS ========== */ event AddressImported(bytes32 name, address destination); } // Internal references // https://docs.synthetix.io/contracts/source/contracts/mixinresolver contract MixinResolver { AddressResolver public resolver; mapping(bytes32 => address) private addressCache; constructor(address _resolver) internal { resolver = AddressResolver(_resolver); } /* ========== INTERNAL FUNCTIONS ========== */ function combineArrays(bytes32[] memory first, bytes32[] memory second) internal pure returns (bytes32[] memory combination) { combination = new bytes32[](first.length + second.length); for (uint i = 0; i < first.length; i++) { combination[i] = first[i]; } for (uint j = 0; j < second.length; j++) { combination[first.length + j] = second[j]; } } /* ========== PUBLIC FUNCTIONS ========== */ // Note: this function is public not external in order for it to be overridden and invoked via super in subclasses function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {} function rebuildCache() public { bytes32[] memory requiredAddresses = resolverAddressesRequired(); // The resolver must call this function whenver it updates its state for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // Note: can only be invoked once the resolver has all the targets needed added address destination = resolver.requireAndGetAddress(name, string(abi.encodePacked("Resolver missing target: ", name))); addressCache[name] = destination; emit CacheUpdated(name, destination); } } /* ========== VIEWS ========== */ function isResolverCached() external view returns (bool) { bytes32[] memory requiredAddresses = resolverAddressesRequired(); for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // false if our cache is invalid or if the resolver doesn't have the required address if (resolver.getAddress(name) != addressCache[name] || addressCache[name] == address(0)) { return false; } } return true; } /* ========== INTERNAL FUNCTIONS ========== */ function requireAndGetAddress(bytes32 name) internal view returns (address) { address _foundAddress = addressCache[name]; require(_foundAddress != address(0), string(abi.encodePacked("Missing address: ", name))); return _foundAddress; } /* ========== EVENTS ========== */ event CacheUpdated(bytes32 name, address destination); } // https://docs.synthetix.io/contracts/source/interfaces/iflexiblestorage interface IFlexibleStorage { // Views function getUIntValue(bytes32 contractName, bytes32 record) external view returns (uint); function getUIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (uint[] memory); function getIntValue(bytes32 contractName, bytes32 record) external view returns (int); function getIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (int[] memory); function getAddressValue(bytes32 contractName, bytes32 record) external view returns (address); function getAddressValues(bytes32 contractName, bytes32[] calldata records) external view returns (address[] memory); function getBoolValue(bytes32 contractName, bytes32 record) external view returns (bool); function getBoolValues(bytes32 contractName, bytes32[] calldata records) external view returns (bool[] memory); function getBytes32Value(bytes32 contractName, bytes32 record) external view returns (bytes32); function getBytes32Values(bytes32 contractName, bytes32[] calldata records) external view returns (bytes32[] memory); // Mutative functions function deleteUIntValue(bytes32 contractName, bytes32 record) external; function deleteIntValue(bytes32 contractName, bytes32 record) external; function deleteAddressValue(bytes32 contractName, bytes32 record) external; function deleteBoolValue(bytes32 contractName, bytes32 record) external; function deleteBytes32Value(bytes32 contractName, bytes32 record) external; function setUIntValue( bytes32 contractName, bytes32 record, uint value ) external; function setUIntValues( bytes32 contractName, bytes32[] calldata records, uint[] calldata values ) external; function setIntValue( bytes32 contractName, bytes32 record, int value ) external; function setIntValues( bytes32 contractName, bytes32[] calldata records, int[] calldata values ) external; function setAddressValue( bytes32 contractName, bytes32 record, address value ) external; function setAddressValues( bytes32 contractName, bytes32[] calldata records, address[] calldata values ) external; function setBoolValue( bytes32 contractName, bytes32 record, bool value ) external; function setBoolValues( bytes32 contractName, bytes32[] calldata records, bool[] calldata values ) external; function setBytes32Value( bytes32 contractName, bytes32 record, bytes32 value ) external; function setBytes32Values( bytes32 contractName, bytes32[] calldata records, bytes32[] calldata values ) external; } // Internal references // https://docs.synthetix.io/contracts/source/contracts/mixinsystemsettings contract MixinSystemSettings is MixinResolver { // must match the one defined SystemSettingsLib, defined in both places due to sol v0.5 limitations bytes32 internal constant SETTING_CONTRACT_NAME = "SystemSettings"; bytes32 internal constant SETTING_WAITING_PERIOD_SECS = "waitingPeriodSecs"; bytes32 internal constant SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR = "priceDeviationThresholdFactor"; bytes32 internal constant SETTING_ISSUANCE_RATIO = "issuanceRatio"; bytes32 internal constant SETTING_FEE_PERIOD_DURATION = "feePeriodDuration"; bytes32 internal constant SETTING_TARGET_THRESHOLD = "targetThreshold"; bytes32 internal constant SETTING_LIQUIDATION_DELAY = "liquidationDelay"; bytes32 internal constant SETTING_LIQUIDATION_RATIO = "liquidationRatio"; bytes32 internal constant SETTING_LIQUIDATION_ESCROW_DURATION = "liquidationEscrowDuration"; bytes32 internal constant SETTING_LIQUIDATION_PENALTY = "liquidationPenalty"; bytes32 internal constant SETTING_SNX_LIQUIDATION_PENALTY = "snxLiquidationPenalty"; bytes32 internal constant SETTING_SELF_LIQUIDATION_PENALTY = "selfLiquidationPenalty"; bytes32 internal constant SETTING_FLAG_REWARD = "flagReward"; bytes32 internal constant SETTING_LIQUIDATE_REWARD = "liquidateReward"; bytes32 internal constant SETTING_RATE_STALE_PERIOD = "rateStalePeriod"; /* ========== Exchange Fees Related ========== */ bytes32 internal constant SETTING_EXCHANGE_FEE_RATE = "exchangeFeeRate"; bytes32 internal constant SETTING_EXCHANGE_DYNAMIC_FEE_THRESHOLD = "exchangeDynamicFeeThreshold"; bytes32 internal constant SETTING_EXCHANGE_DYNAMIC_FEE_WEIGHT_DECAY = "exchangeDynamicFeeWeightDecay"; bytes32 internal constant SETTING_EXCHANGE_DYNAMIC_FEE_ROUNDS = "exchangeDynamicFeeRounds"; bytes32 internal constant SETTING_EXCHANGE_MAX_DYNAMIC_FEE = "exchangeMaxDynamicFee"; /* ========== End Exchange Fees Related ========== */ bytes32 internal constant SETTING_MINIMUM_STAKE_TIME = "minimumStakeTime"; bytes32 internal constant SETTING_AGGREGATOR_WARNING_FLAGS = "aggregatorWarningFlags"; bytes32 internal constant SETTING_TRADING_REWARDS_ENABLED = "tradingRewardsEnabled"; bytes32 internal constant SETTING_DEBT_SNAPSHOT_STALE_TIME = "debtSnapshotStaleTime"; bytes32 internal constant SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT = "crossDomainDepositGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT = "crossDomainEscrowGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT = "crossDomainRewardGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT = "crossDomainWithdrawalGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_FEE_PERIOD_CLOSE_GAS_LIMIT = "crossDomainCloseGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_RELAY_GAS_LIMIT = "crossDomainRelayGasLimit"; bytes32 internal constant SETTING_ETHER_WRAPPER_MAX_ETH = "etherWrapperMaxETH"; bytes32 internal constant SETTING_ETHER_WRAPPER_MINT_FEE_RATE = "etherWrapperMintFeeRate"; bytes32 internal constant SETTING_ETHER_WRAPPER_BURN_FEE_RATE = "etherWrapperBurnFeeRate"; bytes32 internal constant SETTING_WRAPPER_MAX_TOKEN_AMOUNT = "wrapperMaxTokens"; bytes32 internal constant SETTING_WRAPPER_MINT_FEE_RATE = "wrapperMintFeeRate"; bytes32 internal constant SETTING_WRAPPER_BURN_FEE_RATE = "wrapperBurnFeeRate"; bytes32 internal constant SETTING_INTERACTION_DELAY = "interactionDelay"; bytes32 internal constant SETTING_COLLAPSE_FEE_RATE = "collapseFeeRate"; bytes32 internal constant SETTING_ATOMIC_MAX_VOLUME_PER_BLOCK = "atomicMaxVolumePerBlock"; bytes32 internal constant SETTING_ATOMIC_TWAP_WINDOW = "atomicTwapWindow"; bytes32 internal constant SETTING_ATOMIC_EQUIVALENT_FOR_DEX_PRICING = "atomicEquivalentForDexPricing"; bytes32 internal constant SETTING_ATOMIC_EXCHANGE_FEE_RATE = "atomicExchangeFeeRate"; bytes32 internal constant SETTING_ATOMIC_VOLATILITY_CONSIDERATION_WINDOW = "atomicVolConsiderationWindow"; bytes32 internal constant SETTING_ATOMIC_VOLATILITY_UPDATE_THRESHOLD = "atomicVolUpdateThreshold"; bytes32 internal constant SETTING_PURE_CHAINLINK_PRICE_FOR_ATOMIC_SWAPS_ENABLED = "pureChainlinkForAtomicsEnabled"; bytes32 internal constant SETTING_CROSS_SYNTH_TRANSFER_ENABLED = "crossChainSynthTransferEnabled"; bytes32 internal constant CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage"; enum CrossDomainMessageGasLimits {Deposit, Escrow, Reward, Withdrawal, CloseFeePeriod, Relay} struct DynamicFeeConfig { uint threshold; uint weightDecay; uint rounds; uint maxFee; } constructor(address _resolver) internal MixinResolver(_resolver) {} function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { addresses = new bytes32[](1); addresses[0] = CONTRACT_FLEXIBLESTORAGE; } function flexibleStorage() internal view returns (IFlexibleStorage) { return IFlexibleStorage(requireAndGetAddress(CONTRACT_FLEXIBLESTORAGE)); } function _getGasLimitSetting(CrossDomainMessageGasLimits gasLimitType) internal pure returns (bytes32) { if (gasLimitType == CrossDomainMessageGasLimits.Deposit) { return SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Escrow) { return SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Reward) { return SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Withdrawal) { return SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Relay) { return SETTING_CROSS_DOMAIN_RELAY_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.CloseFeePeriod) { return SETTING_CROSS_DOMAIN_FEE_PERIOD_CLOSE_GAS_LIMIT; } else { revert("Unknown gas limit type"); } } function getCrossDomainMessageGasLimit(CrossDomainMessageGasLimits gasLimitType) internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, _getGasLimitSetting(gasLimitType)); } function getTradingRewardsEnabled() internal view returns (bool) { return flexibleStorage().getBoolValue(SETTING_CONTRACT_NAME, SETTING_TRADING_REWARDS_ENABLED); } function getWaitingPeriodSecs() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_WAITING_PERIOD_SECS); } function getPriceDeviationThresholdFactor() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR); } function getIssuanceRatio() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ISSUANCE_RATIO); } function getFeePeriodDuration() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_FEE_PERIOD_DURATION); } function getTargetThreshold() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_TARGET_THRESHOLD); } function getLiquidationDelay() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_DELAY); } function getLiquidationRatio() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_RATIO); } function getLiquidationEscrowDuration() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_ESCROW_DURATION); } function getLiquidationPenalty() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_PENALTY); } function getSnxLiquidationPenalty() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_SNX_LIQUIDATION_PENALTY); } function getSelfLiquidationPenalty() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_SELF_LIQUIDATION_PENALTY); } function getFlagReward() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_FLAG_REWARD); } function getLiquidateReward() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATE_REWARD); } function getRateStalePeriod() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_RATE_STALE_PERIOD); } /* ========== Exchange Related Fees ========== */ function getExchangeFeeRate(bytes32 currencyKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_EXCHANGE_FEE_RATE, currencyKey)) ); } /// @notice Get exchange dynamic fee related keys /// @return threshold, weight decay, rounds, and max fee function getExchangeDynamicFeeConfig() internal view returns (DynamicFeeConfig memory) { bytes32[] memory keys = new bytes32[](4); keys[0] = SETTING_EXCHANGE_DYNAMIC_FEE_THRESHOLD; keys[1] = SETTING_EXCHANGE_DYNAMIC_FEE_WEIGHT_DECAY; keys[2] = SETTING_EXCHANGE_DYNAMIC_FEE_ROUNDS; keys[3] = SETTING_EXCHANGE_MAX_DYNAMIC_FEE; uint[] memory values = flexibleStorage().getUIntValues(SETTING_CONTRACT_NAME, keys); return DynamicFeeConfig({threshold: values[0], weightDecay: values[1], rounds: values[2], maxFee: values[3]}); } /* ========== End Exchange Related Fees ========== */ function getMinimumStakeTime() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_MINIMUM_STAKE_TIME); } function getAggregatorWarningFlags() internal view returns (address) { return flexibleStorage().getAddressValue(SETTING_CONTRACT_NAME, SETTING_AGGREGATOR_WARNING_FLAGS); } function getDebtSnapshotStaleTime() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_DEBT_SNAPSHOT_STALE_TIME); } function getEtherWrapperMaxETH() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ETHER_WRAPPER_MAX_ETH); } function getEtherWrapperMintFeeRate() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ETHER_WRAPPER_MINT_FEE_RATE); } function getEtherWrapperBurnFeeRate() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ETHER_WRAPPER_BURN_FEE_RATE); } function getWrapperMaxTokenAmount(address wrapper) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_WRAPPER_MAX_TOKEN_AMOUNT, wrapper)) ); } function getWrapperMintFeeRate(address wrapper) internal view returns (int) { return flexibleStorage().getIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_WRAPPER_MINT_FEE_RATE, wrapper)) ); } function getWrapperBurnFeeRate(address wrapper) internal view returns (int) { return flexibleStorage().getIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_WRAPPER_BURN_FEE_RATE, wrapper)) ); } function getInteractionDelay(address collateral) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_INTERACTION_DELAY, collateral)) ); } function getCollapseFeeRate(address collateral) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_COLLAPSE_FEE_RATE, collateral)) ); } function getAtomicMaxVolumePerBlock() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ATOMIC_MAX_VOLUME_PER_BLOCK); } function getAtomicTwapWindow() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ATOMIC_TWAP_WINDOW); } function getAtomicEquivalentForDexPricing(bytes32 currencyKey) internal view returns (address) { return flexibleStorage().getAddressValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_ATOMIC_EQUIVALENT_FOR_DEX_PRICING, currencyKey)) ); } function getAtomicExchangeFeeRate(bytes32 currencyKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_ATOMIC_EXCHANGE_FEE_RATE, currencyKey)) ); } function getAtomicVolatilityConsiderationWindow(bytes32 currencyKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_ATOMIC_VOLATILITY_CONSIDERATION_WINDOW, currencyKey)) ); } function getAtomicVolatilityUpdateThreshold(bytes32 currencyKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_ATOMIC_VOLATILITY_UPDATE_THRESHOLD, currencyKey)) ); } function getPureChainlinkPriceForAtomicSwapsEnabled(bytes32 currencyKey) internal view returns (bool) { return flexibleStorage().getBoolValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_PURE_CHAINLINK_PRICE_FOR_ATOMIC_SWAPS_ENABLED, currencyKey)) ); } function getCrossChainSynthTransferEnabled(bytes32 currencyKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_CROSS_SYNTH_TRANSFER_ENABLED, currencyKey)) ); } function getExchangeMaxDynamicFee() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_MAX_DYNAMIC_FEE); } function getExchangeDynamicFeeRounds() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_ROUNDS); } function getExchangeDynamicFeeThreshold() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_THRESHOLD); } function getExchangeDynamicFeeWeightDecay() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXCHANGE_DYNAMIC_FEE_WEIGHT_DECAY); } } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // Libraries // https://docs.synthetix.io/contracts/source/libraries/safedecimalmath library SafeDecimalMath { using SafeMath for uint; /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint public constant UNIT = 10**uint(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(uint x, uint y) internal pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return x.mul(y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(uint x, uint y) internal pure returns (uint) { /* Reintroduce the UNIT factor that will be divided out by y. */ return x.mul(UNIT).div(y); } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function _divideDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint resultTimesTen = x.mul(precisionUnit * 10).div(y); if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(uint i) internal pure returns (uint) { uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } // Computes `a - b`, setting the value to 0 if b > a. function floorsub(uint a, uint b) internal pure returns (uint) { return b >= a ? 0 : a - b; } /* ---------- Utilities ---------- */ /* * Absolute value of the input, returned as a signed number. */ function signedAbs(int x) internal pure returns (int) { return x < 0 ? -x : x; } /* * Absolute value of the input, returned as an unsigned number. */ function abs(int x) internal pure returns (uint) { return uint(signedAbs(x)); } } // https://docs.synthetix.io/contracts/source/interfaces/isystemstatus interface ISystemStatus { struct Status { bool canSuspend; bool canResume; } struct Suspension { bool suspended; // reason is an integer code, // 0 => no reason, 1 => upgrading, 2+ => defined by system usage uint248 reason; } // Views function accessControl(bytes32 section, address account) external view returns (bool canSuspend, bool canResume); function requireSystemActive() external view; function systemSuspended() external view returns (bool); function requireIssuanceActive() external view; function requireExchangeActive() external view; function requireFuturesActive() external view; function requireFuturesMarketActive(bytes32 marketKey) external view; function requireExchangeBetweenSynthsAllowed(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view; function requireSynthActive(bytes32 currencyKey) external view; function synthSuspended(bytes32 currencyKey) external view returns (bool); function requireSynthsActive(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view; function systemSuspension() external view returns (bool suspended, uint248 reason); function issuanceSuspension() external view returns (bool suspended, uint248 reason); function exchangeSuspension() external view returns (bool suspended, uint248 reason); function futuresSuspension() external view returns (bool suspended, uint248 reason); function synthExchangeSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason); function synthSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason); function futuresMarketSuspension(bytes32 marketKey) external view returns (bool suspended, uint248 reason); function getSynthExchangeSuspensions(bytes32[] calldata synths) external view returns (bool[] memory exchangeSuspensions, uint256[] memory reasons); function getSynthSuspensions(bytes32[] calldata synths) external view returns (bool[] memory suspensions, uint256[] memory reasons); function getFuturesMarketSuspensions(bytes32[] calldata marketKeys) external view returns (bool[] memory suspensions, uint256[] memory reasons); // Restricted functions function suspendIssuance(uint256 reason) external; function suspendSynth(bytes32 currencyKey, uint256 reason) external; function suspendFuturesMarket(bytes32 marketKey, uint256 reason) external; function updateAccessControl( bytes32 section, address account, bool canSuspend, bool canResume ) external; } // https://docs.synthetix.io/contracts/source/interfaces/ierc20 interface IERC20 { // ERC20 Optional Views function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); // Views function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); // Mutative functions function transfer(address to, uint value) external returns (bool); function approve(address spender, uint value) external returns (bool); function transferFrom( address from, address to, uint value ) external returns (bool); // Events event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } // https://docs.synthetix.io/contracts/source/interfaces/ICircuitBreaker interface ICircuitBreaker { // Views function isInvalid(address oracleAddress, uint value) external view returns (bool); function priceDeviationThresholdFactor() external view returns (uint); function isDeviationAboveThreshold(uint base, uint comparison) external view returns (bool); function lastValue(address oracleAddress) external view returns (uint); function circuitBroken(address oracleAddress) external view returns (bool); // Mutative functions function resetLastValue(address[] calldata oracleAddresses, uint[] calldata values) external; function probeCircuitBreaker(address oracleAddress, uint value) external returns (bool circuitBroken); } // https://docs.synthetix.io/contracts/source/interfaces/ifeepool interface IFeePool { // Views // solhint-disable-next-line func-name-mixedcase function FEE_ADDRESS() external view returns (address); function feesAvailable(address account) external view returns (uint, uint); function feePeriodDuration() external view returns (uint); function isFeesClaimable(address account) external view returns (bool); function targetThreshold() external view returns (uint); function totalFeesAvailable() external view returns (uint); function totalRewardsAvailable() external view returns (uint); // Mutative Functions function claimFees() external returns (bool); function claimOnBehalf(address claimingForAddress) external returns (bool); function closeCurrentFeePeriod() external; function closeSecondary(uint snxBackedDebt, uint debtShareSupply) external; function recordFeePaid(uint sUSDAmount) external; function setRewardsToDistribute(uint amount) external; } // https://docs.synthetix.io/contracts/source/interfaces/idelegateapprovals interface IDelegateApprovals { // Views function canBurnFor(address authoriser, address delegate) external view returns (bool); function canIssueFor(address authoriser, address delegate) external view returns (bool); function canClaimFor(address authoriser, address delegate) external view returns (bool); function canExchangeFor(address authoriser, address delegate) external view returns (bool); // Mutative function approveAllDelegatePowers(address delegate) external; function removeAllDelegatePowers(address delegate) external; function approveBurnOnBehalf(address delegate) external; function removeBurnOnBehalf(address delegate) external; function approveIssueOnBehalf(address delegate) external; function removeIssueOnBehalf(address delegate) external; function approveClaimOnBehalf(address delegate) external; function removeClaimOnBehalf(address delegate) external; function approveExchangeOnBehalf(address delegate) external; function removeExchangeOnBehalf(address delegate) external; } // https://docs.synthetix.io/contracts/source/interfaces/itradingrewards interface ITradingRewards { /* ========== VIEWS ========== */ function getAvailableRewards() external view returns (uint); function getUnassignedRewards() external view returns (uint); function getRewardsToken() external view returns (address); function getPeriodController() external view returns (address); function getCurrentPeriod() external view returns (uint); function getPeriodIsClaimable(uint periodID) external view returns (bool); function getPeriodIsFinalized(uint periodID) external view returns (bool); function getPeriodRecordedFees(uint periodID) external view returns (uint); function getPeriodTotalRewards(uint periodID) external view returns (uint); function getPeriodAvailableRewards(uint periodID) external view returns (uint); function getUnaccountedFeesForAccountForPeriod(address account, uint periodID) external view returns (uint); function getAvailableRewardsForAccountForPeriod(address account, uint periodID) external view returns (uint); function getAvailableRewardsForAccountForPeriods(address account, uint[] calldata periodIDs) external view returns (uint totalRewards); /* ========== MUTATIVE FUNCTIONS ========== */ function claimRewardsForPeriod(uint periodID) external; function claimRewardsForPeriods(uint[] calldata periodIDs) external; /* ========== RESTRICTED FUNCTIONS ========== */ function recordExchangeFeeForAccount(uint usdFeeAmount, address account) external; function closeCurrentPeriodWithRewards(uint rewards) external; function recoverTokens(address tokenAddress, address recoverAddress) external; function recoverUnassignedRewardTokens(address recoverAddress) external; function recoverAssignedRewardTokensAndDestroyPeriod(address recoverAddress, uint periodID) external; function setPeriodController(address newPeriodController) external; } interface IVirtualSynth { // Views function balanceOfUnderlying(address account) external view returns (uint); function rate() external view returns (uint); function readyToSettle() external view returns (bool); function secsLeftInWaitingPeriod() external view returns (uint); function settled() external view returns (bool); function synth() external view returns (ISynth); // Mutative functions function settle(address account) external; } pragma experimental ABIEncoderV2; // https://docs.synthetix.io/contracts/source/interfaces/iexchanger interface IExchanger { struct ExchangeEntrySettlement { bytes32 src; uint amount; bytes32 dest; uint reclaim; uint rebate; uint srcRoundIdAtPeriodEnd; uint destRoundIdAtPeriodEnd; uint timestamp; } struct ExchangeEntry { uint sourceRate; uint destinationRate; uint destinationAmount; uint exchangeFeeRate; uint exchangeDynamicFeeRate; uint roundIdForSrc; uint roundIdForDest; uint sourceAmountAfterSettlement; } // Views function calculateAmountAfterSettlement( address from, bytes32 currencyKey, uint amount, uint refunded ) external view returns (uint amountAfterSettlement); function isSynthRateInvalid(bytes32 currencyKey) external view returns (bool); function maxSecsLeftInWaitingPeriod(address account, bytes32 currencyKey) external view returns (uint); function settlementOwing(address account, bytes32 currencyKey) external view returns ( uint reclaimAmount, uint rebateAmount, uint numEntries ); function hasWaitingPeriodOrSettlementOwing(address account, bytes32 currencyKey) external view returns (bool); function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint); function dynamicFeeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint feeRate, bool tooVolatile); function getAmountsForExchange( uint sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns ( uint amountReceived, uint fee, uint exchangeFeeRate ); function priceDeviationThresholdFactor() external view returns (uint); function waitingPeriodSecs() external view returns (uint); function lastExchangeRate(bytes32 currencyKey) external view returns (uint); // Mutative functions function exchange( address exchangeForAddress, address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress, bool virtualSynth, address rewardAddress, bytes32 trackingCode ) external returns (uint amountReceived, IVirtualSynth vSynth); function exchangeAtomically( address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress, bytes32 trackingCode, uint minAmount ) external returns (uint amountReceived); function settle(address from, bytes32 currencyKey) external returns ( uint reclaimed, uint refunded, uint numEntries ); } // Used to have strongly-typed access to internal mutative functions in Synthetix interface ISynthetixInternal { function emitExchangeTracking( bytes32 trackingCode, bytes32 toCurrencyKey, uint256 toAmount, uint256 fee ) external; function emitSynthExchange( address account, bytes32 fromCurrencyKey, uint fromAmount, bytes32 toCurrencyKey, uint toAmount, address toAddress ) external; function emitAtomicSynthExchange( address account, bytes32 fromCurrencyKey, uint fromAmount, bytes32 toCurrencyKey, uint toAmount, address toAddress ) external; function emitExchangeReclaim( address account, bytes32 currencyKey, uint amount ) external; function emitExchangeRebate( address account, bytes32 currencyKey, uint amount ) external; } interface IExchangerInternalDebtCache { function updateCachedSynthDebtsWithRates(bytes32[] calldata currencyKeys, uint[] calldata currencyRates) external; function updateCachedSynthDebts(bytes32[] calldata currencyKeys) external; } // https://docs.synthetix.io/contracts/source/interfaces/IDirectIntegration interface IDirectIntegrationManager { struct ParameterIntegrationSettings { bytes32 currencyKey; address dexPriceAggregator; address atomicEquivalentForDexPricing; uint atomicExchangeFeeRate; uint atomicTwapWindow; uint atomicMaxVolumePerBlock; uint atomicVolatilityConsiderationWindow; uint atomicVolatilityUpdateThreshold; uint exchangeFeeRate; uint exchangeMaxDynamicFee; uint exchangeDynamicFeeRounds; uint exchangeDynamicFeeThreshold; uint exchangeDynamicFeeWeightDecay; } function getExchangeParameters(address integration, bytes32 key) external view returns (ParameterIntegrationSettings memory settings); function setExchangeParameters( address integration, bytes32[] calldata currencyKeys, ParameterIntegrationSettings calldata params ) external; } // https://docs.synthetix.io/contracts/source/interfaces/iexchangerates interface IExchangeRates { // Structs struct RateAndUpdatedTime { uint216 rate; uint40 time; } // Views function aggregators(bytes32 currencyKey) external view returns (address); function aggregatorWarningFlags() external view returns (address); function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool); function anyRateIsInvalidAtRound(bytes32[] calldata currencyKeys, uint[] calldata roundIds) external view returns (bool); function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory); function effectiveValue( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint value); function effectiveValueAndRates( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns ( uint value, uint sourceRate, uint destinationRate ); function effectiveValueAndRatesAtRound( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, uint roundIdForSrc, uint roundIdForDest ) external view returns ( uint value, uint sourceRate, uint destinationRate ); function effectiveAtomicValueAndRates( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns ( uint value, uint systemValue, uint systemSourceRate, uint systemDestinationRate ); function effectiveAtomicValueAndRates( IDirectIntegrationManager.ParameterIntegrationSettings calldata sourceSettings, uint sourceAmount, IDirectIntegrationManager.ParameterIntegrationSettings calldata destinationSettings, IDirectIntegrationManager.ParameterIntegrationSettings calldata usdSettings ) external view returns ( uint value, uint systemValue, uint systemSourceRate, uint systemDestinationRate ); function getCurrentRoundId(bytes32 currencyKey) external view returns (uint); function getLastRoundIdBeforeElapsedSecs( bytes32 currencyKey, uint startingRoundId, uint startingTimestamp, uint timediff ) external view returns (uint); function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256); function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time); function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time); function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid); function rateForCurrency(bytes32 currencyKey) external view returns (uint); function rateIsFlagged(bytes32 currencyKey) external view returns (bool); function rateIsInvalid(bytes32 currencyKey) external view returns (bool); function rateIsStale(bytes32 currencyKey) external view returns (bool); function rateStalePeriod() external view returns (uint); function ratesAndUpdatedTimeForCurrencyLastNRounds( bytes32 currencyKey, uint numRounds, uint roundId ) external view returns (uint[] memory rates, uint[] memory times); function ratesAndInvalidForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory rates, bool anyRateInvalid); function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory); function synthTooVolatileForAtomicExchange(bytes32 currencyKey) external view returns (bool); function synthTooVolatileForAtomicExchange(IDirectIntegrationManager.ParameterIntegrationSettings calldata settings) external view returns (bool); function rateWithSafetyChecks(bytes32 currencyKey) external returns ( uint rate, bool broken, bool invalid ); } // https://docs.synthetix.io/contracts/source/interfaces/iexchangestate interface IExchangeState { // Views struct ExchangeEntry { bytes32 src; uint amount; bytes32 dest; uint amountReceived; uint exchangeFeeRate; uint timestamp; uint roundIdForSrc; uint roundIdForDest; } function getLengthOfEntries(address account, bytes32 currencyKey) external view returns (uint); function getEntryAt( address account, bytes32 currencyKey, uint index ) external view returns ( bytes32 src, uint amount, bytes32 dest, uint amountReceived, uint exchangeFeeRate, uint timestamp, uint roundIdForSrc, uint roundIdForDest ); function getMaxTimestamp(address account, bytes32 currencyKey) external view returns (uint); // Mutative functions function appendExchangeEntry( address account, bytes32 src, uint amount, bytes32 dest, uint amountReceived, uint exchangeFeeRate, uint timestamp, uint roundIdForSrc, uint roundIdForDest ) external; function removeEntries(address account, bytes32 currencyKey) external; } interface IDebtCache { // Views function cachedDebt() external view returns (uint); function cachedSynthDebt(bytes32 currencyKey) external view returns (uint); function cacheTimestamp() external view returns (uint); function cacheInvalid() external view returns (bool); function cacheStale() external view returns (bool); function isInitialized() external view returns (bool); function currentSynthDebts(bytes32[] calldata currencyKeys) external view returns ( uint[] memory debtValues, uint futuresDebt, uint excludedDebt, bool anyRateIsInvalid ); function cachedSynthDebts(bytes32[] calldata currencyKeys) external view returns (uint[] memory debtValues); function totalNonSnxBackedDebt() external view returns (uint excludedDebt, bool isInvalid); function currentDebt() external view returns (uint debt, bool anyRateIsInvalid); function cacheInfo() external view returns ( uint debt, uint timestamp, bool isInvalid, bool isStale ); function excludedIssuedDebts(bytes32[] calldata currencyKeys) external view returns (uint[] memory excludedDebts); // Mutative functions function updateCachedSynthDebts(bytes32[] calldata currencyKeys) external; function updateCachedSynthDebtWithRate(bytes32 currencyKey, uint currencyRate) external; function updateCachedSynthDebtsWithRates(bytes32[] calldata currencyKeys, uint[] calldata currencyRates) external; function updateDebtCacheValidity(bool currentlyInvalid) external; function purgeCachedSynthDebt(bytes32 currencyKey) external; function takeDebtSnapshot() external; function recordExcludedDebtChange(bytes32 currencyKey, int256 delta) external; function updateCachedsUSDDebt(int amount) external; function importExcludedIssuedDebts(IDebtCache prevDebtCache, IIssuer prevIssuer) external; } // https://docs.synthetix.io/contracts/source/interfaces/isynthetix interface ISynthetix { // Views function anySynthOrSNXRateIsInvalid() external view returns (bool anyRateInvalid); function availableCurrencyKeys() external view returns (bytes32[] memory); function availableSynthCount() external view returns (uint); function availableSynths(uint index) external view returns (ISynth); function collateral(address account) external view returns (uint); function collateralisationRatio(address issuer) external view returns (uint); function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint); function isWaitingPeriod(bytes32 currencyKey) external view returns (bool); function maxIssuableSynths(address issuer) external view returns (uint maxIssuable); function remainingIssuableSynths(address issuer) external view returns ( uint maxIssuable, uint alreadyIssued, uint totalSystemDebt ); function synths(bytes32 currencyKey) external view returns (ISynth); function synthsByAddress(address synthAddress) external view returns (bytes32); function totalIssuedSynths(bytes32 currencyKey) external view returns (uint); function totalIssuedSynthsExcludeOtherCollateral(bytes32 currencyKey) external view returns (uint); function transferableSynthetix(address account) external view returns (uint transferable); function getFirstNonZeroEscrowIndex(address account) external view returns (uint); // Mutative Functions function burnSynths(uint amount) external; function burnSynthsOnBehalf(address burnForAddress, uint amount) external; function burnSynthsToTarget() external; function burnSynthsToTargetOnBehalf(address burnForAddress) external; function exchange( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external returns (uint amountReceived); function exchangeOnBehalf( address exchangeForAddress, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external returns (uint amountReceived); function exchangeWithTracking( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address rewardAddress, bytes32 trackingCode ) external returns (uint amountReceived); function exchangeWithTrackingForInitiator( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address rewardAddress, bytes32 trackingCode ) external returns (uint amountReceived); function exchangeOnBehalfWithTracking( address exchangeForAddress, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address rewardAddress, bytes32 trackingCode ) external returns (uint amountReceived); function exchangeWithVirtual( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, bytes32 trackingCode ) external returns (uint amountReceived, IVirtualSynth vSynth); function exchangeAtomically( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, bytes32 trackingCode, uint minAmount ) external returns (uint amountReceived); function issueMaxSynths() external; function issueMaxSynthsOnBehalf(address issueForAddress) external; function issueSynths(uint amount) external; function issueSynthsOnBehalf(address issueForAddress, uint amount) external; function mint() external returns (bool); function settle(bytes32 currencyKey) external returns ( uint reclaimed, uint refunded, uint numEntries ); // Liquidations function liquidateDelinquentAccount(address account) external returns (bool); function liquidateDelinquentAccountEscrowIndex(address account, uint escrowStartIndex) external returns (bool); function liquidateSelf() external returns (bool); // Restricted Functions function mintSecondary(address account, uint amount) external; function mintSecondaryRewards(uint amount) external; function burnSecondary(address account, uint amount) external; } library ExchangeSettlementLib { using SafeMath for uint256; using SafeDecimalMath for uint256; struct ResolvedAddresses { IExchangeState exchangeState; IExchangeRates exchangeRates; ICircuitBreaker circuitBreaker; IExchangerInternalDebtCache debtCache; IIssuer issuer; ISynthetix synthetix; } bytes32 internal constant sUSD = "sUSD"; function internalSettle( ResolvedAddresses calldata resolvedAddresses, address from, bytes32 currencyKey, bool updateCache, uint waitingPeriod ) external returns ( uint reclaimed, uint refunded, uint numEntriesSettled ) { require( maxSecsLeftInWaitingPeriod(resolvedAddresses.exchangeState, from, currencyKey, waitingPeriod) == 0, "Cannot settle during waiting period" ); (uint reclaimAmount, uint rebateAmount, uint entries, IExchanger.ExchangeEntrySettlement[] memory settlements) = _settlementOwing(resolvedAddresses, from, currencyKey, waitingPeriod); if (reclaimAmount > rebateAmount) { reclaimed = reclaimAmount.sub(rebateAmount); _reclaim(resolvedAddresses, from, currencyKey, reclaimed); } else if (rebateAmount > reclaimAmount) { refunded = rebateAmount.sub(reclaimAmount); _refund(resolvedAddresses, from, currencyKey, refunded); } // by checking a reclaim or refund we also check that the currency key is still a valid synth, // as the deviation check will return 0 if the synth has been removed. if (updateCache && (reclaimed > 0 || refunded > 0)) { bytes32[] memory key = new bytes32[](1); key[0] = currencyKey; resolvedAddresses.debtCache.updateCachedSynthDebts(key); } // emit settlement event for each settled exchange entry for (uint i = 0; i < settlements.length; i++) { emit ExchangeEntrySettled( from, settlements[i].src, settlements[i].amount, settlements[i].dest, settlements[i].reclaim, settlements[i].rebate, settlements[i].srcRoundIdAtPeriodEnd, settlements[i].destRoundIdAtPeriodEnd, settlements[i].timestamp ); } numEntriesSettled = entries; // Now remove all entries, even if no reclaim and no rebate resolvedAddresses.exchangeState.removeEntries(from, currencyKey); } function maxSecsLeftInWaitingPeriod( IExchangeState exchangeState, address account, bytes32 currencyKey, uint waitingPeriod ) public view returns (uint) { return _secsLeftInWaitingPeriodForExchange(exchangeState.getMaxTimestamp(account, currencyKey), waitingPeriod); } function _secsLeftInWaitingPeriodForExchange(uint timestamp, uint waitingPeriod) internal view returns (uint) { if (timestamp == 0 || now >= timestamp.add(waitingPeriod)) { return 0; } return timestamp.add(waitingPeriod).sub(now); } function _reclaim( ResolvedAddresses memory resolvedAddresses, address from, bytes32 currencyKey, uint amount ) internal { // burn amount from user resolvedAddresses.issuer.synths(currencyKey).burn(from, amount); ISynthetixInternal(address(resolvedAddresses.synthetix)).emitExchangeReclaim(from, currencyKey, amount); } function _refund( ResolvedAddresses memory resolvedAddresses, address from, bytes32 currencyKey, uint amount ) internal { // issue amount to user resolvedAddresses.issuer.synths(currencyKey).issue(from, amount); ISynthetixInternal(address(resolvedAddresses.synthetix)).emitExchangeRebate(from, currencyKey, amount); } function hasWaitingPeriodOrSettlementOwing( ResolvedAddresses calldata resolvedAddresses, address account, bytes32 currencyKey, uint waitingPeriod ) external view returns (bool) { if (maxSecsLeftInWaitingPeriod(resolvedAddresses.exchangeState, account, currencyKey, waitingPeriod) != 0) { return true; } (uint reclaimAmount, , , ) = _settlementOwing(resolvedAddresses, account, currencyKey, waitingPeriod); return reclaimAmount > 0; } function settlementOwing( ResolvedAddresses calldata resolvedAddresses, address account, bytes32 currencyKey, uint waitingPeriod ) external view returns ( uint reclaimAmount, uint rebateAmount, uint numEntries, IExchanger.ExchangeEntrySettlement[] memory ) { return _settlementOwing(resolvedAddresses, account, currencyKey, waitingPeriod); } // Internal function to aggregate each individual rebate and reclaim entry for a synth function _settlementOwing( ResolvedAddresses memory resolvedAddresses, address account, bytes32 currencyKey, uint waitingPeriod ) internal view returns ( uint reclaimAmount, uint rebateAmount, uint numEntries, IExchanger.ExchangeEntrySettlement[] memory ) { // Need to sum up all reclaim and rebate amounts for the user and the currency key numEntries = resolvedAddresses.exchangeState.getLengthOfEntries(account, currencyKey); // For each unsettled exchange IExchanger.ExchangeEntrySettlement[] memory settlements = new IExchanger.ExchangeEntrySettlement[](numEntries); for (uint i = 0; i < numEntries; i++) { // fetch the entry from storage IExchangeState.ExchangeEntry memory exchangeEntry = _getExchangeEntry(resolvedAddresses.exchangeState, account, currencyKey, i); // determine the last round ids for src and dest pairs when period ended or latest if not over (uint srcRoundIdAtPeriodEnd, uint destRoundIdAtPeriodEnd) = _getRoundIdsAtPeriodEnd(resolvedAddresses.exchangeRates, exchangeEntry, waitingPeriod); // given these round ids, determine what effective value they should have received uint amountShouldHaveReceived; { (uint destinationAmount, , ) = resolvedAddresses.exchangeRates.effectiveValueAndRatesAtRound( exchangeEntry.src, exchangeEntry.amount, exchangeEntry.dest, srcRoundIdAtPeriodEnd, destRoundIdAtPeriodEnd ); // and deduct the fee from this amount using the exchangeFeeRate from storage amountShouldHaveReceived = _deductFeesFromAmount(destinationAmount, exchangeEntry.exchangeFeeRate); } // SIP-65 settlements where the amount at end of waiting period is beyond the threshold, then // settle with no reclaim or rebate bool sip65condition = resolvedAddresses.circuitBreaker.isDeviationAboveThreshold( exchangeEntry.amountReceived, amountShouldHaveReceived ); uint reclaim; uint rebate; if (!sip65condition) { if (exchangeEntry.amountReceived > amountShouldHaveReceived) { // if they received more than they should have, add to the reclaim tally reclaim = exchangeEntry.amountReceived.sub(amountShouldHaveReceived); reclaimAmount = reclaimAmount.add(reclaim); } else if (amountShouldHaveReceived > exchangeEntry.amountReceived) { // if less, add to the rebate tally rebate = amountShouldHaveReceived.sub(exchangeEntry.amountReceived); rebateAmount = rebateAmount.add(rebate); } } settlements[i] = IExchanger.ExchangeEntrySettlement({ src: exchangeEntry.src, amount: exchangeEntry.amount, dest: exchangeEntry.dest, reclaim: reclaim, rebate: rebate, srcRoundIdAtPeriodEnd: srcRoundIdAtPeriodEnd, destRoundIdAtPeriodEnd: destRoundIdAtPeriodEnd, timestamp: exchangeEntry.timestamp }); } return (reclaimAmount, rebateAmount, numEntries, settlements); } function _getExchangeEntry( IExchangeState exchangeState, address account, bytes32 currencyKey, uint index ) internal view returns (IExchangeState.ExchangeEntry memory) { ( bytes32 src, uint amount, bytes32 dest, uint amountReceived, uint exchangeFeeRate, uint timestamp, uint roundIdForSrc, uint roundIdForDest ) = exchangeState.getEntryAt(account, currencyKey, index); return IExchangeState.ExchangeEntry({ src: src, amount: amount, dest: dest, amountReceived: amountReceived, exchangeFeeRate: exchangeFeeRate, timestamp: timestamp, roundIdForSrc: roundIdForSrc, roundIdForDest: roundIdForDest }); } function _getRoundIdsAtPeriodEnd( IExchangeRates exRates, IExchangeState.ExchangeEntry memory exchangeEntry, uint waitingPeriod ) internal view returns (uint srcRoundIdAtPeriodEnd, uint destRoundIdAtPeriodEnd) { srcRoundIdAtPeriodEnd = exRates.getLastRoundIdBeforeElapsedSecs( exchangeEntry.src, exchangeEntry.roundIdForSrc, exchangeEntry.timestamp, waitingPeriod ); destRoundIdAtPeriodEnd = exRates.getLastRoundIdBeforeElapsedSecs( exchangeEntry.dest, exchangeEntry.roundIdForDest, exchangeEntry.timestamp, waitingPeriod ); } function _deductFeesFromAmount(uint destinationAmount, uint exchangeFeeRate) internal pure returns (uint amountReceived) { amountReceived = destinationAmount.multiplyDecimal(SafeDecimalMath.unit().sub(exchangeFeeRate)); } function appendExchange( ResolvedAddresses calldata resolvedAddresses, address account, bytes32 src, uint amount, bytes32 dest, uint amountReceived, uint exchangeFeeRate ) external { uint roundIdForSrc = resolvedAddresses.exchangeRates.getCurrentRoundId(src); uint roundIdForDest = resolvedAddresses.exchangeRates.getCurrentRoundId(dest); resolvedAddresses.exchangeState.appendExchangeEntry( account, src, amount, dest, amountReceived, exchangeFeeRate, now, roundIdForSrc, roundIdForDest ); emit ExchangeEntryAppended( account, src, amount, dest, amountReceived, exchangeFeeRate, roundIdForSrc, roundIdForDest ); } // ========== EVENTS ========== event ExchangeEntryAppended( address indexed account, bytes32 src, uint256 amount, bytes32 dest, uint256 amountReceived, uint256 exchangeFeeRate, uint256 roundIdForSrc, uint256 roundIdForDest ); event ExchangeEntrySettled( address indexed from, bytes32 src, uint256 amount, bytes32 dest, uint256 reclaim, uint256 rebate, uint256 srcRoundIdAtPeriodEnd, uint256 destRoundIdAtPeriodEnd, uint256 exchangeTimestamp ); } // Inheritance // Internal references // https://docs.synthetix.io/contracts/source/contracts/proxy contract Proxy is Owned { Proxyable public target; constructor(address _owner) public Owned(_owner) {} function setTarget(Proxyable _target) external onlyOwner { target = _target; emit TargetUpdated(_target); } function _emit( bytes calldata callData, uint numTopics, bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes32 topic4 ) external onlyTarget { uint size = callData.length; bytes memory _callData = callData; assembly { /* The first 32 bytes of callData contain its length (as specified by the abi). * Length is assumed to be a uint256 and therefore maximum of 32 bytes * in length. It is also leftpadded to be a multiple of 32 bytes. * This means moving call_data across 32 bytes guarantees we correctly access * the data itself. */ switch numTopics case 0 { log0(add(_callData, 32), size) } case 1 { log1(add(_callData, 32), size, topic1) } case 2 { log2(add(_callData, 32), size, topic1, topic2) } case 3 { log3(add(_callData, 32), size, topic1, topic2, topic3) } case 4 { log4(add(_callData, 32), size, topic1, topic2, topic3, topic4) } } } // solhint-disable no-complex-fallback function() external payable { // Mutable call setting Proxyable.messageSender as this is using call not delegatecall target.setMessageSender(msg.sender); assembly { let free_ptr := mload(0x40) calldatacopy(free_ptr, 0, calldatasize) /* We must explicitly forward ether to the underlying contract as well. */ let result := call(gas, sload(target_slot), callvalue, free_ptr, calldatasize, 0, 0) returndatacopy(free_ptr, 0, returndatasize) if iszero(result) { revert(free_ptr, returndatasize) } return(free_ptr, returndatasize) } } modifier onlyTarget { require(Proxyable(msg.sender) == target, "Must be proxy target"); _; } event TargetUpdated(Proxyable newTarget); } // Inheritance // Internal references // https://docs.synthetix.io/contracts/source/contracts/proxyable contract Proxyable is Owned { // This contract should be treated like an abstract contract /* The proxy this contract exists behind. */ Proxy public proxy; /* The caller of the proxy, passed through to this contract. * Note that every function using this member must apply the onlyProxy or * optionalProxy modifiers, otherwise their invocations can use stale values. */ address public messageSender; constructor(address payable _proxy) internal { // This contract is abstract, and thus cannot be instantiated directly require(owner != address(0), "Owner must be set"); proxy = Proxy(_proxy); emit ProxyUpdated(_proxy); } function setProxy(address payable _proxy) external onlyOwner { proxy = Proxy(_proxy); emit ProxyUpdated(_proxy); } function setMessageSender(address sender) external onlyProxy { messageSender = sender; } modifier onlyProxy { _onlyProxy(); _; } function _onlyProxy() private view { require(Proxy(msg.sender) == proxy, "Only the proxy can call"); } modifier optionalProxy { _optionalProxy(); _; } function _optionalProxy() private { if (Proxy(msg.sender) != proxy && messageSender != msg.sender) { messageSender = msg.sender; } } modifier optionalProxy_onlyOwner { _optionalProxy_onlyOwner(); _; } // solhint-disable-next-line func-name-mixedcase function _optionalProxy_onlyOwner() private { if (Proxy(msg.sender) != proxy && messageSender != msg.sender) { messageSender = msg.sender; } require(messageSender == owner, "Owner only function"); } event ProxyUpdated(address proxyAddress); } // Inheritance // Libraries // Internal references // https://docs.synthetix.io/contracts/source/contracts/exchanger contract Exchanger is Owned, MixinSystemSettings, IExchanger { using SafeMath for uint; using SafeDecimalMath for uint; bytes32 public constant CONTRACT_NAME = "Exchanger"; bytes32 internal constant sUSD = "sUSD"; /* ========== ADDRESS RESOLVER CONFIGURATION ========== */ bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus"; bytes32 private constant CONTRACT_EXCHANGESTATE = "ExchangeState"; bytes32 private constant CONTRACT_EXRATES = "ExchangeRates"; bytes32 private constant CONTRACT_SYNTHETIX = "Synthetix"; bytes32 private constant CONTRACT_FEEPOOL = "FeePool"; bytes32 private constant CONTRACT_TRADING_REWARDS = "TradingRewards"; bytes32 private constant CONTRACT_DELEGATEAPPROVALS = "DelegateApprovals"; bytes32 private constant CONTRACT_ISSUER = "Issuer"; bytes32 private constant CONTRACT_DEBTCACHE = "DebtCache"; bytes32 private constant CONTRACT_CIRCUIT_BREAKER = "CircuitBreaker"; bytes32 private constant CONTRACT_DIRECT_INTEGRATION_MANAGER = "DirectIntegrationManager"; constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) {} /* ========== VIEWS ========== */ function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](11); newAddresses[0] = CONTRACT_SYSTEMSTATUS; newAddresses[1] = CONTRACT_EXCHANGESTATE; newAddresses[2] = CONTRACT_EXRATES; newAddresses[3] = CONTRACT_SYNTHETIX; newAddresses[4] = CONTRACT_FEEPOOL; newAddresses[5] = CONTRACT_TRADING_REWARDS; newAddresses[6] = CONTRACT_DELEGATEAPPROVALS; newAddresses[7] = CONTRACT_ISSUER; newAddresses[8] = CONTRACT_DEBTCACHE; newAddresses[9] = CONTRACT_CIRCUIT_BREAKER; newAddresses[10] = CONTRACT_DIRECT_INTEGRATION_MANAGER; addresses = combineArrays(existingAddresses, newAddresses); } function systemStatus() internal view returns (ISystemStatus) { return ISystemStatus(requireAndGetAddress(CONTRACT_SYSTEMSTATUS)); } function exchangeState() internal view returns (IExchangeState) { return IExchangeState(requireAndGetAddress(CONTRACT_EXCHANGESTATE)); } function exchangeRates() internal view returns (IExchangeRates) { return IExchangeRates(requireAndGetAddress(CONTRACT_EXRATES)); } function circuitBreaker() internal view returns (ICircuitBreaker) { return ICircuitBreaker(requireAndGetAddress(CONTRACT_CIRCUIT_BREAKER)); } function synthetix() internal view returns (ISynthetix) { return ISynthetix(requireAndGetAddress(CONTRACT_SYNTHETIX)); } function feePool() internal view returns (IFeePool) { return IFeePool(requireAndGetAddress(CONTRACT_FEEPOOL)); } function tradingRewards() internal view returns (ITradingRewards) { return ITradingRewards(requireAndGetAddress(CONTRACT_TRADING_REWARDS)); } function delegateApprovals() internal view returns (IDelegateApprovals) { return IDelegateApprovals(requireAndGetAddress(CONTRACT_DELEGATEAPPROVALS)); } function issuer() internal view returns (IIssuer) { return IIssuer(requireAndGetAddress(CONTRACT_ISSUER)); } function debtCache() internal view returns (IExchangerInternalDebtCache) { return IExchangerInternalDebtCache(requireAndGetAddress(CONTRACT_DEBTCACHE)); } function directIntegrationManager() internal view returns (IDirectIntegrationManager) { return IDirectIntegrationManager(requireAndGetAddress(CONTRACT_DIRECT_INTEGRATION_MANAGER)); } function resolvedAddresses() internal view returns (ExchangeSettlementLib.ResolvedAddresses memory) { return ExchangeSettlementLib.ResolvedAddresses( exchangeState(), exchangeRates(), circuitBreaker(), debtCache(), issuer(), synthetix() ); } function waitingPeriodSecs() external view returns (uint) { return getWaitingPeriodSecs(); } function tradingRewardsEnabled() external view returns (bool) { return getTradingRewardsEnabled(); } function priceDeviationThresholdFactor() external view returns (uint) { return getPriceDeviationThresholdFactor(); } function lastExchangeRate(bytes32 currencyKey) external view returns (uint) { return circuitBreaker().lastValue(address(exchangeRates().aggregators(currencyKey))); } function settlementOwing(address account, bytes32 currencyKey) public view returns ( uint reclaimAmount, uint rebateAmount, uint numEntries ) { (reclaimAmount, rebateAmount, numEntries, ) = ExchangeSettlementLib.settlementOwing( resolvedAddresses(), account, currencyKey, getWaitingPeriodSecs() ); } function hasWaitingPeriodOrSettlementOwing(address account, bytes32 currencyKey) external view returns (bool) { return ExchangeSettlementLib.hasWaitingPeriodOrSettlementOwing( resolvedAddresses(), account, currencyKey, getWaitingPeriodSecs() ); } function maxSecsLeftInWaitingPeriod(address account, bytes32 currencyKey) public view returns (uint) { return ExchangeSettlementLib._secsLeftInWaitingPeriodForExchange( exchangeState().getMaxTimestamp(account, currencyKey), getWaitingPeriodSecs() ); } /* ========== SETTERS ========== */ function calculateAmountAfterSettlement( address from, bytes32 currencyKey, uint amount, uint refunded ) public view returns (uint amountAfterSettlement) { amountAfterSettlement = amount; // balance of a synth will show an amount after settlement uint balanceOfSourceAfterSettlement = IERC20(address(issuer().synths(currencyKey))).balanceOf(from); // when there isn't enough supply (either due to reclamation settlement or because the number is too high) if (amountAfterSettlement > balanceOfSourceAfterSettlement) { // then the amount to exchange is reduced to their remaining supply amountAfterSettlement = balanceOfSourceAfterSettlement; } if (refunded > 0) { amountAfterSettlement = amountAfterSettlement.add(refunded); } } function isSynthRateInvalid(bytes32 currencyKey) external view returns (bool) { (, bool invalid) = exchangeRates().rateAndInvalid(currencyKey); return invalid; } /* ========== MUTATIVE FUNCTIONS ========== */ function exchange( address exchangeForAddress, address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress, bool virtualSynth, address rewardAddress, bytes32 trackingCode ) external onlySynthetixorSynth returns (uint amountReceived, IVirtualSynth vSynth) { uint fee; if (from != exchangeForAddress) { require(delegateApprovals().canExchangeFor(exchangeForAddress, from), "Not approved to act on behalf"); } IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = _exchangeSettings(from, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = _exchangeSettings(from, destinationCurrencyKey); (amountReceived, fee, vSynth) = _exchange( exchangeForAddress, sourceSettings, sourceAmount, destinationSettings, destinationAddress, virtualSynth ); _processTradingRewards(fee, rewardAddress); if (trackingCode != bytes32(0)) { _emitTrackingEvent(trackingCode, destinationCurrencyKey, amountReceived, fee); } } function exchangeAtomically( address, bytes32, uint, bytes32, address, bytes32, uint ) external returns (uint) { _notImplemented(); } function _emitTrackingEvent( bytes32 trackingCode, bytes32 toCurrencyKey, uint256 toAmount, uint256 fee ) internal { ISynthetixInternal(address(synthetix())).emitExchangeTracking(trackingCode, toCurrencyKey, toAmount, fee); } function _processTradingRewards(uint fee, address rewardAddress) internal { if (fee > 0 && rewardAddress != address(0) && getTradingRewardsEnabled()) { tradingRewards().recordExchangeFeeForAccount(fee, rewardAddress); } } function _updateSNXIssuedDebtOnExchange(bytes32[2] memory currencyKeys, uint[2] memory currencyRates) internal { bool includesSUSD = currencyKeys[0] == sUSD || currencyKeys[1] == sUSD; uint numKeys = includesSUSD ? 2 : 3; bytes32[] memory keys = new bytes32[](numKeys); keys[0] = currencyKeys[0]; keys[1] = currencyKeys[1]; uint[] memory rates = new uint[](numKeys); rates[0] = currencyRates[0]; rates[1] = currencyRates[1]; if (!includesSUSD) { keys[2] = sUSD; // And we'll also update sUSD to account for any fees if it wasn't one of the exchanged currencies rates[2] = SafeDecimalMath.unit(); } // Note that exchanges can't invalidate the debt cache, since if a rate is invalid, // the exchange will have failed already. debtCache().updateCachedSynthDebtsWithRates(keys, rates); } function _settleAndCalcSourceAmountRemaining( uint sourceAmount, address from, bytes32 sourceCurrencyKey ) internal returns (uint sourceAmountAfterSettlement) { (, uint refunded, uint numEntriesSettled) = ExchangeSettlementLib.internalSettle( resolvedAddresses(), from, sourceCurrencyKey, false, getWaitingPeriodSecs() ); sourceAmountAfterSettlement = sourceAmount; // when settlement was required if (numEntriesSettled > 0) { // ensure the sourceAmount takes this into account sourceAmountAfterSettlement = calculateAmountAfterSettlement(from, sourceCurrencyKey, sourceAmount, refunded); } } function _exchange( address from, IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, uint sourceAmount, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings, address destinationAddress, bool virtualSynth ) internal returns ( uint amountReceived, uint fee, IVirtualSynth vSynth ) { if (!_ensureCanExchange(sourceSettings.currencyKey, destinationSettings.currencyKey, sourceAmount)) { return (0, 0, IVirtualSynth(0)); } // Using struct to resolve stack too deep error IExchanger.ExchangeEntry memory entry; ExchangeSettlementLib.ResolvedAddresses memory addrs = resolvedAddresses(); entry.roundIdForSrc = addrs.exchangeRates.getCurrentRoundId(sourceSettings.currencyKey); entry.roundIdForDest = addrs.exchangeRates.getCurrentRoundId(destinationSettings.currencyKey); entry.sourceAmountAfterSettlement = _settleAndCalcSourceAmountRemaining( sourceAmount, from, sourceSettings.currencyKey ); // If, after settlement the user has no balance left (highly unlikely), then return to prevent // emitting events of 0 and don't revert so as to ensure the settlement queue is emptied if (entry.sourceAmountAfterSettlement == 0) { return (0, 0, IVirtualSynth(0)); } (entry.destinationAmount, entry.sourceRate, entry.destinationRate) = addrs .exchangeRates .effectiveValueAndRatesAtRound( sourceSettings.currencyKey, entry.sourceAmountAfterSettlement, destinationSettings.currencyKey, entry.roundIdForSrc, entry.roundIdForDest ); // rates must also be good for the round we are doing _ensureCanExchangeAtRound( sourceSettings.currencyKey, destinationSettings.currencyKey, entry.roundIdForSrc, entry.roundIdForDest ); bool tooVolatile; (entry.exchangeFeeRate, tooVolatile) = _feeRateForExchangeAtRounds( sourceSettings, destinationSettings, entry.roundIdForSrc, entry.roundIdForDest ); if (tooVolatile) { // do not exchange if rates are too volatile, this to prevent charging // dynamic fees that are over the max value return (0, 0, IVirtualSynth(0)); } amountReceived = ExchangeSettlementLib._deductFeesFromAmount(entry.destinationAmount, entry.exchangeFeeRate); // Note: `fee` is denominated in the destinationCurrencyKey. fee = entry.destinationAmount.sub(amountReceived); // Note: We don't need to check their balance as the _convert() below will do a safe subtraction which requires // the subtraction to not overflow, which would happen if their balance is not sufficient. vSynth = _convert( sourceSettings.currencyKey, from, entry.sourceAmountAfterSettlement, destinationSettings.currencyKey, amountReceived, destinationAddress, virtualSynth ); // When using a virtual synth, it becomes the destinationAddress for event and settlement tracking if (vSynth != IVirtualSynth(0)) { destinationAddress = address(vSynth); } // Remit the fee if required if (fee > 0) { // Normalize fee to sUSD // Note: `fee` is being reused to avoid stack too deep errors. fee = addrs.exchangeRates.effectiveValue(destinationSettings.currencyKey, fee, sUSD); // Remit the fee in sUSDs issuer().synths(sUSD).issue(feePool().FEE_ADDRESS(), fee); // Tell the fee pool about this feePool().recordFeePaid(fee); } // Note: As of this point, `fee` is denominated in sUSD. // Nothing changes as far as issuance data goes because the total value in the system hasn't changed. // But we will update the debt snapshot in case exchange rates have fluctuated since the last exchange // in these currencies _updateSNXIssuedDebtOnExchange( [sourceSettings.currencyKey, destinationSettings.currencyKey], [entry.sourceRate, entry.destinationRate] ); // Let the DApps know there was a Synth exchange ISynthetixInternal(address(synthetix())).emitSynthExchange( from, sourceSettings.currencyKey, entry.sourceAmountAfterSettlement, destinationSettings.currencyKey, amountReceived, destinationAddress ); // iff the waiting period is gt 0 if (getWaitingPeriodSecs() > 0) { // persist the exchange information for the dest key ExchangeSettlementLib.appendExchange( addrs, destinationAddress, sourceSettings.currencyKey, entry.sourceAmountAfterSettlement, destinationSettings.currencyKey, amountReceived, entry.exchangeFeeRate ); } } function _convert( bytes32 sourceCurrencyKey, address from, uint sourceAmountAfterSettlement, bytes32 destinationCurrencyKey, uint amountReceived, address recipient, bool virtualSynth ) internal returns (IVirtualSynth vSynth) { // Burn the source amount issuer().synths(sourceCurrencyKey).burn(from, sourceAmountAfterSettlement); // Issue their new synths ISynth dest = issuer().synths(destinationCurrencyKey); if (virtualSynth) { Proxyable synth = Proxyable(address(dest)); vSynth = _createVirtualSynth(IERC20(address(synth.proxy())), recipient, amountReceived, destinationCurrencyKey); dest.issue(address(vSynth), amountReceived); } else { dest.issue(recipient, amountReceived); } } function _createVirtualSynth( IERC20, address, uint, bytes32 ) internal returns (IVirtualSynth) { _notImplemented(); } // Note: this function can intentionally be called by anyone on behalf of anyone else (the caller just pays the gas) function settle(address from, bytes32 currencyKey) external returns ( uint reclaimed, uint refunded, uint numEntriesSettled ) { systemStatus().requireSynthActive(currencyKey); return ExchangeSettlementLib.internalSettle(resolvedAddresses(), from, currencyKey, true, getWaitingPeriodSecs()); } /* ========== INTERNAL FUNCTIONS ========== */ // gets the exchange parameters for a given direct integration (returns default params if no overrides exist) function _exchangeSettings(address from, bytes32 currencyKey) internal view returns (IDirectIntegrationManager.ParameterIntegrationSettings memory settings) { settings = directIntegrationManager().getExchangeParameters(from, currencyKey); } // runs basic checks and calls `rateWithSafetyChecks` (which can trigger circuit breakers) // returns if there are any problems found with the rate of the given currencyKey but not reverted function _ensureCanExchange( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey, uint sourceAmount ) internal returns (bool) { require(sourceCurrencyKey != destinationCurrencyKey, "Can't be same synth"); require(sourceAmount > 0, "Zero amount"); (, bool srcBroken, bool srcStaleOrInvalid) = sourceCurrencyKey != sUSD ? exchangeRates().rateWithSafetyChecks(sourceCurrencyKey) : (0, false, false); (, bool dstBroken, bool dstStaleOrInvalid) = destinationCurrencyKey != sUSD ? exchangeRates().rateWithSafetyChecks(destinationCurrencyKey) : (0, false, false); require(!srcStaleOrInvalid, "src rate stale or flagged"); require(!dstStaleOrInvalid, "dest rate stale or flagged"); return !srcBroken && !dstBroken; } // runs additional checks to verify a rate is valid at a specific round` function _ensureCanExchangeAtRound( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey, uint roundIdForSrc, uint roundIdForDest ) internal view { require(sourceCurrencyKey != destinationCurrencyKey, "Can't be same synth"); bytes32[] memory synthKeys = new bytes32[](2); synthKeys[0] = sourceCurrencyKey; synthKeys[1] = destinationCurrencyKey; uint[] memory roundIds = new uint[](2); roundIds[0] = roundIdForSrc; roundIds[1] = roundIdForDest; require(!exchangeRates().anyRateIsInvalidAtRound(synthKeys, roundIds), "src/dest rate stale or flagged"); } /* ========== Exchange Related Fees ========== */ /// @notice public function to get the total fee rate for a given exchange /// @param sourceCurrencyKey The source currency key /// @param destinationCurrencyKey The destination currency key /// @return The exchange fee rate, and whether the rates are too volatile function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint) { IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = _exchangeSettings(msg.sender, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = _exchangeSettings(msg.sender, destinationCurrencyKey); (uint feeRate, bool tooVolatile) = _feeRateForExchange(sourceSettings, destinationSettings); require(!tooVolatile, "too volatile"); return feeRate; } /// @notice public function to get the dynamic fee rate for a given exchange /// @param sourceCurrencyKey The source currency key /// @param destinationCurrencyKey The destination currency key /// @return The exchange dynamic fee rate and if rates are too volatile function dynamicFeeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint feeRate, bool tooVolatile) { IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = _exchangeSettings(msg.sender, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = _exchangeSettings(msg.sender, destinationCurrencyKey); return _dynamicFeeRateForExchange(sourceSettings, destinationSettings); } /// @notice Calculate the exchange fee for a given source and destination currency key /// @param sourceSettings The source currency key /// @param destinationSettings The destination currency key /// @return The exchange fee rate /// @return The exchange dynamic fee rate and if rates are too volatile function _feeRateForExchange( IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings ) internal view returns (uint feeRate, bool tooVolatile) { // Get the exchange fee rate as per the source currencyKey and destination currencyKey uint baseRate = sourceSettings.exchangeFeeRate.add(destinationSettings.exchangeFeeRate); uint dynamicFee; (dynamicFee, tooVolatile) = _dynamicFeeRateForExchange(sourceSettings, destinationSettings); return (baseRate.add(dynamicFee), tooVolatile); } /// @notice Calculate the exchange fee for a given source and destination currency key /// @param sourceSettings The source currency key /// @param destinationSettings The destination currency key /// @param roundIdForSrc The round id of the source currency. /// @param roundIdForDest The round id of the target currency. /// @return The exchange fee rate /// @return The exchange dynamic fee rate function _feeRateForExchangeAtRounds( IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings, uint roundIdForSrc, uint roundIdForDest ) internal view returns (uint feeRate, bool tooVolatile) { // Get the exchange fee rate as per the source currencyKey and destination currencyKey uint baseRate = sourceSettings.exchangeFeeRate.add(destinationSettings.exchangeFeeRate); uint dynamicFee; (dynamicFee, tooVolatile) = _dynamicFeeRateForExchangeAtRounds( sourceSettings, destinationSettings, roundIdForSrc, roundIdForDest ); return (baseRate.add(dynamicFee), tooVolatile); } function _dynamicFeeRateForExchange( IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings ) internal view returns (uint dynamicFee, bool tooVolatile) { (uint dynamicFeeDst, bool dstVolatile) = _dynamicFeeRateForCurrency(destinationSettings); (uint dynamicFeeSrc, bool srcVolatile) = _dynamicFeeRateForCurrency(sourceSettings); dynamicFee = dynamicFeeDst.add(dynamicFeeSrc); // cap to maxFee bool overMax = dynamicFee > sourceSettings.exchangeMaxDynamicFee; dynamicFee = overMax ? sourceSettings.exchangeMaxDynamicFee : dynamicFee; return (dynamicFee, overMax || dstVolatile || srcVolatile); } function _dynamicFeeRateForExchangeAtRounds( IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings, uint roundIdForSrc, uint roundIdForDest ) internal view returns (uint dynamicFee, bool tooVolatile) { (uint dynamicFeeDst, bool dstVolatile) = _dynamicFeeRateForCurrencyRound(destinationSettings, roundIdForDest); (uint dynamicFeeSrc, bool srcVolatile) = _dynamicFeeRateForCurrencyRound(sourceSettings, roundIdForSrc); dynamicFee = dynamicFeeDst.add(dynamicFeeSrc); // cap to maxFee bool overMax = dynamicFee > sourceSettings.exchangeMaxDynamicFee; dynamicFee = overMax ? sourceSettings.exchangeMaxDynamicFee : dynamicFee; return (dynamicFee, overMax || dstVolatile || srcVolatile); } /// @notice Get dynamic dynamicFee for a given currency key (SIP-184) /// @param settings The given currency key /// @return The dynamic fee and if it exceeds max dynamic fee set in config function _dynamicFeeRateForCurrency(IDirectIntegrationManager.ParameterIntegrationSettings memory settings) internal view returns (uint dynamicFee, bool tooVolatile) { // no dynamic dynamicFee for sUSD or too few rounds if (settings.currencyKey == sUSD || settings.exchangeDynamicFeeRounds <= 1) { return (0, false); } uint roundId = exchangeRates().getCurrentRoundId(settings.currencyKey); return _dynamicFeeRateForCurrencyRound(settings, roundId); } /// @notice Get dynamicFee for a given currency key (SIP-184) /// @param settings The given currency key /// @param roundId The round id /// @return The dynamic fee and if it exceeds max dynamic fee set in config function _dynamicFeeRateForCurrencyRound( IDirectIntegrationManager.ParameterIntegrationSettings memory settings, uint roundId ) internal view returns (uint dynamicFee, bool tooVolatile) { // no dynamic dynamicFee for sUSD or too few rounds if (settings.currencyKey == sUSD || settings.exchangeDynamicFeeRounds <= 1) { return (0, false); } uint[] memory prices; (prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds( settings.currencyKey, settings.exchangeDynamicFeeRounds, roundId ); dynamicFee = _dynamicFeeCalculation( prices, settings.exchangeDynamicFeeThreshold, settings.exchangeDynamicFeeWeightDecay ); // cap to maxFee bool overMax = dynamicFee > settings.exchangeMaxDynamicFee; dynamicFee = overMax ? settings.exchangeMaxDynamicFee : dynamicFee; return (dynamicFee, overMax); } /// @notice Calculate dynamic fee according to SIP-184 /// @param prices A list of prices from the current round to the previous rounds /// @param threshold A threshold to clip the price deviation ratop /// @param weightDecay A weight decay constant /// @return uint dynamic fee rate as decimal function _dynamicFeeCalculation( uint[] memory prices, uint threshold, uint weightDecay ) internal pure returns (uint) { // don't underflow if (prices.length == 0) { return 0; } uint dynamicFee = 0; // start with 0 // go backwards in price array for (uint i = prices.length - 1; i > 0; i--) { // apply decay from previous round (will be 0 for first round) dynamicFee = dynamicFee.multiplyDecimal(weightDecay); // calculate price deviation uint deviation = _thresholdedAbsDeviationRatio(prices[i - 1], prices[i], threshold); // add to total fee dynamicFee = dynamicFee.add(deviation); } return dynamicFee; } /// absolute price deviation ratio used by dynamic fee calculation /// deviationRatio = (abs(current - previous) / previous) - threshold /// if negative, zero is returned function _thresholdedAbsDeviationRatio( uint price, uint previousPrice, uint threshold ) internal pure returns (uint) { if (previousPrice == 0) { return 0; // don't divide by zero } // abs difference between prices uint absDelta = price > previousPrice ? price - previousPrice : previousPrice - price; // relative to previous price uint deviationRatio = absDelta.divideDecimal(previousPrice); // only the positive difference from threshold return deviationRatio > threshold ? deviationRatio - threshold : 0; } function getAmountsForExchange( uint sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns ( uint amountReceived, uint fee, uint exchangeFeeRate ) { IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = _exchangeSettings(msg.sender, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = _exchangeSettings(msg.sender, destinationCurrencyKey); require(sourceCurrencyKey == sUSD || !exchangeRates().rateIsInvalid(sourceCurrencyKey), "src synth rate invalid"); require( destinationCurrencyKey == sUSD || !exchangeRates().rateIsInvalid(destinationCurrencyKey), "dest synth rate invalid" ); // The checks are added for consistency with the checks performed in _exchange() // The reverts (instead of no-op returns) are used order to prevent incorrect usage in calling contracts // (The no-op in _exchange() is in order to trigger system suspension if needed) // check synths active systemStatus().requireSynthActive(sourceCurrencyKey); systemStatus().requireSynthActive(destinationCurrencyKey); bool tooVolatile; (exchangeFeeRate, tooVolatile) = _feeRateForExchange(sourceSettings, destinationSettings); // check rates volatility result require(!tooVolatile, "exchange rates too volatile"); (uint destinationAmount, , ) = exchangeRates().effectiveValueAndRates(sourceCurrencyKey, sourceAmount, destinationCurrencyKey); amountReceived = ExchangeSettlementLib._deductFeesFromAmount(destinationAmount, exchangeFeeRate); fee = destinationAmount.sub(amountReceived); } function _notImplemented() internal pure { revert("Cannot be run on this layer"); } // ========== MODIFIERS ========== modifier onlySynthetixorSynth() { ISynthetix _synthetix = synthetix(); require( msg.sender == address(_synthetix) || _synthetix.synthsByAddress(msg.sender) != bytes32(0), "Exchanger: Only synthetix or a synth contract can perform this action" ); _; } // ========== EVENTS ========== // note bot hof these events are actually emitted from `ExchangeSettlementLib` // but they are defined here for interface reasons event ExchangeEntryAppended( address indexed account, bytes32 src, uint256 amount, bytes32 dest, uint256 amountReceived, uint256 exchangeFeeRate, uint256 roundIdForSrc, uint256 roundIdForDest ); event ExchangeEntrySettled( address indexed from, bytes32 src, uint256 amount, bytes32 dest, uint256 reclaim, uint256 rebate, uint256 srcRoundIdAtPeriodEnd, uint256 destRoundIdAtPeriodEnd, uint256 exchangeTimestamp ); } // https://docs.synthetix.io/contracts/source/contracts/minimalproxyfactory contract MinimalProxyFactory { function _cloneAsMinimalProxy(address _base, string memory _revertMsg) internal returns (address clone) { bytes memory createData = _generateMinimalProxyCreateData(_base); assembly { clone := create( 0, // no value add(createData, 0x20), // data 55 // data is always 55 bytes (10 constructor + 45 code) ) } // If CREATE fails for some reason, address(0) is returned require(clone != address(0), _revertMsg); } function _generateMinimalProxyCreateData(address _base) internal pure returns (bytes memory) { return abi.encodePacked( //---- constructor ----- bytes10(0x3d602d80600a3d3981f3), //---- proxy code ----- bytes10(0x363d3d373d3d3d363d73), _base, bytes15(0x5af43d82803e903d91602b57fd5bf3) ); } } // Inheritance // Internal references interface IVirtualSynthInternal { function initialize( IERC20 _synth, IAddressResolver _resolver, address _recipient, uint _amount, bytes32 _currencyKey ) external; } // https://docs.synthetix.io/contracts/source/contracts/exchangerwithfeereclamationalternatives contract ExchangerWithFeeRecAlternatives is MinimalProxyFactory, Exchanger { bytes32 public constant CONTRACT_NAME = "ExchangerWithFeeRecAlternatives"; using SafeMath for uint; struct ExchangeVolumeAtPeriod { uint64 time; uint192 volume; } ExchangeVolumeAtPeriod public lastAtomicVolume; constructor(address _owner, address _resolver) public MinimalProxyFactory() Exchanger(_owner, _resolver) {} /* ========== ADDRESS RESOLVER CONFIGURATION ========== */ bytes32 private constant CONTRACT_VIRTUALSYNTH_MASTERCOPY = "VirtualSynthMastercopy"; function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = Exchanger.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](1); newAddresses[0] = CONTRACT_VIRTUALSYNTH_MASTERCOPY; addresses = combineArrays(existingAddresses, newAddresses); } /* ========== VIEWS ========== */ function atomicMaxVolumePerBlock() external view returns (uint) { return getAtomicMaxVolumePerBlock(); } function feeRateForAtomicExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint exchangeFeeRate) { IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = _exchangeSettings(msg.sender, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = _exchangeSettings(msg.sender, destinationCurrencyKey); exchangeFeeRate = _feeRateForAtomicExchange(sourceSettings, destinationSettings); } function getAmountsForAtomicExchange( uint sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns ( uint amountReceived, uint fee, uint exchangeFeeRate ) { IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = _exchangeSettings(msg.sender, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = _exchangeSettings(msg.sender, destinationCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory usdSettings = _exchangeSettings(msg.sender, sUSD); (amountReceived, fee, exchangeFeeRate, , , ) = _getAmountsForAtomicExchangeMinusFees( sourceAmount, sourceSettings, destinationSettings, usdSettings ); } /* ========== MUTATIVE FUNCTIONS ========== */ function exchangeAtomically( address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress, bytes32 trackingCode, uint minAmount ) external onlySynthetixorSynth returns (uint amountReceived) { uint fee; (amountReceived, fee) = _exchangeAtomically( from, sourceCurrencyKey, sourceAmount, destinationCurrencyKey, destinationAddress ); require(amountReceived >= minAmount, "The amount received is below the minimum amount specified."); _processTradingRewards(fee, destinationAddress); if (trackingCode != bytes32(0)) { _emitTrackingEvent(trackingCode, destinationCurrencyKey, amountReceived, fee); } } /* ========== INTERNAL FUNCTIONS ========== */ function _virtualSynthMastercopy() internal view returns (address) { return requireAndGetAddress(CONTRACT_VIRTUALSYNTH_MASTERCOPY); } function _createVirtualSynth( IERC20 synth, address recipient, uint amount, bytes32 currencyKey ) internal returns (IVirtualSynth) { // prevent inverse synths from being allowed due to purgeability require(currencyKey[0] != 0x69, "Cannot virtualize this synth"); IVirtualSynthInternal vSynth = IVirtualSynthInternal(_cloneAsMinimalProxy(_virtualSynthMastercopy(), "Could not create new vSynth")); vSynth.initialize(synth, resolver, recipient, amount, currencyKey); emit VirtualSynthCreated(address(synth), recipient, address(vSynth), currencyKey, amount); return IVirtualSynth(address(vSynth)); } function _exchangeAtomically( address from, bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, address destinationAddress ) internal returns (uint amountReceived, uint fee) { uint sourceAmountAfterSettlement; uint exchangeFeeRate; uint systemSourceRate; uint systemDestinationRate; { IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = _exchangeSettings(from, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = _exchangeSettings(from, destinationCurrencyKey); if (!_ensureCanExchange(sourceCurrencyKey, destinationCurrencyKey, sourceAmount)) { return (0, 0); } require(!exchangeRates().synthTooVolatileForAtomicExchange(sourceSettings), "Src synth too volatile"); require(!exchangeRates().synthTooVolatileForAtomicExchange(destinationSettings), "Dest synth too volatile"); sourceAmountAfterSettlement = _settleAndCalcSourceAmountRemaining(sourceAmount, from, sourceCurrencyKey); // If, after settlement the user has no balance left (highly unlikely), then return to prevent // emitting events of 0 and don't revert so as to ensure the settlement queue is emptied if (sourceAmountAfterSettlement == 0) { return (0, 0); } // sometimes we need parameters for USD and USD has parameters which could be overridden IDirectIntegrationManager.ParameterIntegrationSettings memory usdSettings = _exchangeSettings(from, sUSD); uint systemConvertedAmount; // Note: also ensures the given synths are allowed to be atomically exchanged ( amountReceived, // output amount with fee taken out (denominated in dest currency) fee, // fee amount (denominated in dest currency) exchangeFeeRate, // applied fee rate systemConvertedAmount, // current system value without fees (denominated in dest currency) systemSourceRate, // current system rate for src currency systemDestinationRate // current system rate for dest currency ) = _getAmountsForAtomicExchangeMinusFees( sourceAmountAfterSettlement, sourceSettings, destinationSettings, usdSettings ); // Sanity check atomic output's value against current system value (checking atomic rates) require( !circuitBreaker().isDeviationAboveThreshold(systemConvertedAmount, amountReceived.add(fee)), "Atomic rate deviates too much" ); // Determine sUSD value of exchange uint sourceSusdValue; if (sourceCurrencyKey == sUSD) { // Use after-settled amount as this is amount converted (not sourceAmount) sourceSusdValue = sourceAmountAfterSettlement; } else if (destinationCurrencyKey == sUSD) { // In this case the systemConvertedAmount would be the fee-free sUSD value of the source synth sourceSusdValue = systemConvertedAmount; } else { // Otherwise, convert source to sUSD value (uint amountReceivedInUSD, uint sUsdFee, , , , ) = _getAmountsForAtomicExchangeMinusFees( sourceAmountAfterSettlement, sourceSettings, usdSettings, usdSettings ); sourceSusdValue = amountReceivedInUSD.add(sUsdFee); } // Check and update atomic volume limit _checkAndUpdateAtomicVolume(sourceSettings, sourceSusdValue); } // Note: We don't need to check their balance as the _convert() below will do a safe subtraction which requires // the subtraction to not overflow, which would happen if their balance is not sufficient. _convert( sourceCurrencyKey, from, sourceAmountAfterSettlement, destinationCurrencyKey, amountReceived, destinationAddress, false // no vsynths ); // Remit the fee if required if (fee > 0) { // Normalize fee to sUSD // Note: `fee` is being reused to avoid stack too deep errors. fee = exchangeRates().effectiveValue(destinationCurrencyKey, fee, sUSD); // Remit the fee in sUSDs issuer().synths(sUSD).issue(feePool().FEE_ADDRESS(), fee); // Tell the fee pool about this feePool().recordFeePaid(fee); } // Note: As of this point, `fee` is denominated in sUSD. // Note: this update of the debt snapshot will not be accurate because the atomic exchange // was executed with a different rate than the system rate. To be perfect, issuance data, // priced in system rates, should have been adjusted on the src and dest synth. // The debt pool is expected to be deprecated soon, and so we don't bother with being // perfect here. For now, an inaccuracy will slowly accrue over time with increasing atomic // exchange volume. _updateSNXIssuedDebtOnExchange( [sourceCurrencyKey, destinationCurrencyKey], [systemSourceRate, systemDestinationRate] ); // Let the DApps know there was a Synth exchange ISynthetixInternal(address(synthetix())).emitSynthExchange( from, sourceCurrencyKey, sourceAmountAfterSettlement, destinationCurrencyKey, amountReceived, destinationAddress ); // Emit separate event to track atomic exchanges ISynthetixInternal(address(synthetix())).emitAtomicSynthExchange( from, sourceCurrencyKey, sourceAmountAfterSettlement, destinationCurrencyKey, amountReceived, destinationAddress ); // No need to persist any exchange information, as no settlement is required for atomic exchanges } function _checkAndUpdateAtomicVolume( IDirectIntegrationManager.ParameterIntegrationSettings memory settings, uint sourceSusdValue ) internal { uint currentVolume = uint(lastAtomicVolume.time) == block.timestamp ? uint(lastAtomicVolume.volume).add(sourceSusdValue) : sourceSusdValue; require(currentVolume <= settings.atomicMaxVolumePerBlock, "Surpassed volume limit"); lastAtomicVolume.time = uint64(block.timestamp); lastAtomicVolume.volume = uint192(currentVolume); // Protected by volume limit check above } function _feeRateForAtomicExchange( IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings ) internal view returns (uint) { // Get the exchange fee rate as per source and destination currencyKey uint baseRate = sourceSettings.atomicExchangeFeeRate.add(destinationSettings.atomicExchangeFeeRate); if (baseRate == 0) { // If no atomic rate was set, fallback to the regular exchange rate baseRate = sourceSettings.exchangeFeeRate.add(destinationSettings.exchangeFeeRate); } return baseRate; } function _getAmountsForAtomicExchangeMinusFees( uint sourceAmount, IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory usdSettings ) internal view returns ( uint amountReceived, uint fee, uint exchangeFeeRate, uint systemConvertedAmount, uint systemSourceRate, uint systemDestinationRate ) { uint destinationAmount; (destinationAmount, systemConvertedAmount, systemSourceRate, systemDestinationRate) = exchangeRates() .effectiveAtomicValueAndRates(sourceSettings, sourceAmount, destinationSettings, usdSettings); exchangeFeeRate = _feeRateForAtomicExchange(sourceSettings, destinationSettings); amountReceived = ExchangeSettlementLib._deductFeesFromAmount(destinationAmount, exchangeFeeRate); fee = destinationAmount.sub(amountReceived); } event VirtualSynthCreated( address indexed synth, address indexed recipient, address vSynth, bytes32 currencyKey, uint amount ); }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_resolver","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"src","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"dest","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundIdForSrc","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundIdForDest","type":"uint256"}],"name":"ExchangeEntryAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"bytes32","name":"src","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"dest","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"reclaim","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rebate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"srcRoundIdAtPeriodEnd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destRoundIdAtPeriodEnd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeTimestamp","type":"uint256"}],"name":"ExchangeEntrySettled","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":true,"internalType":"address","name":"synth","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"vSynth","type":"address"},{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VirtualSynthCreated","type":"event"},{"constant":true,"inputs":[],"name":"CONTRACT_NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"atomicMaxVolumePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"refunded","type":"uint256"}],"name":"calculateAmountAfterSettlement","outputs":[{"internalType":"uint256","name":"amountAfterSettlement","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"dynamicFeeRateForExchange","outputs":[{"internalType":"uint256","name":"feeRate","type":"uint256"},{"internalType":"bool","name":"tooVolatile","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"exchangeForAddress","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"bool","name":"virtualSynth","type":"bool"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bytes32","name":"trackingCode","type":"bytes32"}],"name":"exchange","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"},{"internalType":"contract IVirtualSynth","name":"vSynth","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"bytes32","name":"trackingCode","type":"bytes32"},{"internalType":"uint256","name":"minAmount","type":"uint256"}],"name":"exchangeAtomically","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"feeRateForAtomicExchange","outputs":[{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"feeRateForExchange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"getAmountsForAtomicExchange","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"getAmountsForExchange","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"hasWaitingPeriodOrSettlementOwing","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"isSynthRateInvalid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastAtomicVolume","outputs":[{"internalType":"uint64","name":"time","type":"uint64"},{"internalType":"uint192","name":"volume","type":"uint192"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"lastExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"maxSecsLeftInWaitingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"priceDeviationThresholdFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"settle","outputs":[{"internalType":"uint256","name":"reclaimed","type":"uint256"},{"internalType":"uint256","name":"refunded","type":"uint256"},{"internalType":"uint256","name":"numEntriesSettled","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"settlementOwing","outputs":[{"internalType":"uint256","name":"reclaimAmount","type":"uint256"},{"internalType":"uint256","name":"rebateAmount","type":"uint256"},{"internalType":"uint256","name":"numEntries","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tradingRewardsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"waitingPeriodSecs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162005a5938038062005a59833981016040819052620000349162000100565b81818080836001600160a01b0381166200006b5760405162461bcd60e51b81526004016200006290620001bc565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91620000b891849062000196565b60405180910390a150600280546001600160a01b0319166001600160a01b039290921691909117905550620002179350505050565b8051620000fa81620001fd565b92915050565b600080604083850312156200011457600080fd5b6000620001228585620000ed565b92505060206200013585828601620000ed565b9150509250929050565b6200014a81620001e9565b82525050565b6200014a81620001d7565b60006200016a601983620001ce565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b60408101620001a682856200013f565b620001b5602083018462000150565b9392505050565b60208082528101620000fa816200015b565b90815260200190565b60006001600160a01b038216620000fa565b6000620000fa826000620000fa82620001d7565b6200020881620001d7565b81146200021457600080fd5b50565b61583280620002276000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c8063614d08f8116100f95780638e52049c11610097578063c39def0b11610071578063c39def0b14610379578063d6f32e061461039a578063dc703e73146103ad578063f450aa34146103c0576101c4565b80638e52049c14610353578063a4bca13114610369578063c193f0d814610371576101c4565b80637dd1a57a116100d35780637dd1a57a1461031b578063892571171461032e578063899ffef4146103365780638da5cb5b1461034b576101c4565b8063614d08f814610303578063741853601461030b57806379ba509714610313576101c4565b80632af64bd3116101665780634c268fc8116101405780634c268fc8146102a75780634f8633d2146102ba57806353a47bb7146102db57806357af302c146102f0576101c4565b80632af64bd31461027757806333a768801461028c578063372a395a1461029f576101c4565b80631627540c116101a25780631627540c1461021a57806319d5c6651461022f5780631a5c6095146102515780631b16802c14610264576101c4565b806304f3bcec146101c9578063059c29ec146101e75780630ae81a5e14610207575b600080fd5b6101d16103d3565b6040516101de9190615368565b60405180910390f35b6101fa6101f536600461442e565b6103e2565b6040516101de919061528f565b6101fa61021536600461461e565b610482565b61022d61022836600461432e565b6104bf565b005b61024261023d36600461442e565b61051d565b6040516101de9392919061530e565b6101fa61025f36600461461e565b6105d0565b61024261027236600461442e565b61063c565b61027f61074f565b6040516101de9190615281565b6101fa61029a366004614468565b610867565b6101fa610981565b6101fa6102b5366004614504565b610990565b6102cd6102c836600461436a565b610ac1565b6040516101de92919061566b565b6102e3610ca8565b6040516101de9190615177565b61027f6102fe3660046145e2565b610cb7565b6101fa610d44565b61022d610d68565b61022d610ebe565b6101fa6103293660046145e2565b610f5a565b6101fa611061565b61033e61106b565b6040516101de919061524b565b6102e36110e0565b61035b6110ef565b6040516101de929190615686565b6101fa611111565b61027f61111b565b61038c61038736600461461e565b611125565b6040516101de929190615650565b61027f6103a836600461442e565b611168565b6102426103bb3660046146f7565b611205565b6102426103ce3660046146f7565b61126f565b6002546001600160a01b031681565b60006104796103ef6115ab565b6001600160a01b031663f1406dc885856040518363ffffffff1660e01b815260040161041c9291906151ae565b60206040518083038186803b15801561043457600080fd5b505afa158015610448573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061046c9190810190614600565b6104746115c6565b611672565b90505b92915050565b600061048c613f07565b61049633856116bd565b90506104a0613f07565b6104aa33856116bd565b90506104b6828261174b565b95945050505050565b6104c761178a565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290610512908390615177565b60405180910390a150565b600080600073aa5a3d7f04e15b22eb3664b56310aa18a3527ec7630a0ecd1b6105446117b6565b878761054e6115c6565b6040518563ffffffff1660e01b815260040161056d94939291906155ac565b60006040518083038186803b15801561058557600080fd5b505af4158015610599573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105c1919081019061477d565b50919790965090945092505050565b60006105da613f07565b6105e433856116bd565b90506105ee613f07565b6105f833856116bd565b9050600080610607848461184f565b9150915080156106325760405162461bcd60e51b81526004016106299061549f565b60405180910390fd5b5095945050505050565b600080600061064961189e565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b8152600401610674919061528f565b60006040518083038186803b15801561068c57600080fd5b505afa1580156106a0573d6000803e3d6000fd5b5050505073aa5a3d7f04e15b22eb3664b56310aa18a3527ec76377cd29a56106c66117b6565b878760016106d26115c6565b6040518663ffffffff1660e01b81526004016106f2959493929190615567565b60606040518083038186803b15801561070a57600080fd5b505af415801561071e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610742919081019061473a565b9250925092509250925092565b6000606061075b61106b565b905060005b815181101561085d57600082828151811061077757fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a721906107c890859060040161528f565b60206040518083038186803b1580156107e057600080fd5b505afa1580156107f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610818919081019061434c565b6001600160a01b031614158061084357506000818152600360205260409020546001600160a01b0316155b156108545760009350505050610864565b50600101610760565b5060019150505b90565b6000806108726118b8565b9050336001600160a01b038216148061090857506040516316b2213f60e01b81526000906001600160a01b038316906316b2213f906108b5903390600401615185565b60206040518083038186803b1580156108cd57600080fd5b505afa1580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109059190810190614600565b14155b6109245760405162461bcd60e51b81526004016106299061546f565b60006109338a8a8a8a8a6118cf565b9093509050838310156109585760405162461bcd60e51b81526004016106299061545f565b6109628187611f6a565b84156109745761097485888584612001565b5050979650505050505050565b600061098b612072565b905090565b81600061099b6120da565b6001600160a01b03166332608039866040518263ffffffff1660e01b81526004016109c6919061528f565b60206040518083038186803b1580156109de57600080fd5b505afa1580156109f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a16919081019061463d565b6001600160a01b03166370a08231876040518263ffffffff1660e01b8152600401610a419190615177565b60206040518083038186803b158015610a5957600080fd5b505afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a919190810190614600565b905080821115610a9f578091505b8215610ab857610ab5828463ffffffff6120ee16565b91505b50949350505050565b6000806000610ace6118b8565b9050336001600160a01b0382161480610b6457506040516316b2213f60e01b81526000906001600160a01b038316906316b2213f90610b11903390600401615185565b60206040518083038186803b158015610b2957600080fd5b505afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b619190810190614600565b14155b610b805760405162461bcd60e51b81526004016106299061546f565b60008c6001600160a01b03168c6001600160a01b031614610c3c57610ba3612113565b6001600160a01b031663faf431bb8e8e6040518363ffffffff1660e01b8152600401610bd0929190615193565b60206040518083038186803b158015610be857600080fd5b505afa158015610bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c2091908101906145c4565b610c3c5760405162461bcd60e51b8152600401610629906153df565b610c44613f07565b610c4e8d8d6116bd565b9050610c58613f07565b610c628e8c6116bd565b9050610c728f838e848e8e612132565b9197509095509250610c848389611f6a565b8615610c9657610c96878c8886612001565b50505050995099975050505050505050565b6001546001600160a01b031681565b600080610cc26127b5565b6001600160a01b0316630c71cd23846040518263ffffffff1660e01b8152600401610ced919061528f565b604080518083038186803b158015610d0457600080fd5b505afa158015610d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3c919081019061467a565b949350505050565b7f45786368616e67657257697468466565526563416c7465726e6174697665730081565b6060610d7261106b565b905060005b8151811015610eba576000828281518110610d8e57fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610dd0919061516c565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610dfc9291906152ee565b60206040518083038186803b158015610e1457600080fd5b505afa158015610e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4c919081019061434c565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa6890610ea8908490849061529d565b60405180910390a15050600101610d77565b5050565b6001546001600160a01b03163314610ee85760405162461bcd60e51b8152600401610629906153cf565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c92610f2b926001600160a01b0391821692911690615193565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000610f646127d0565b6001600160a01b031663ba03e93f610f7a6127b5565b6001600160a01b0316637103353e856040518263ffffffff1660e01b8152600401610fa5919061528f565b60206040518083038186803b158015610fbd57600080fd5b505afa158015610fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ff5919081019061434c565b6040518263ffffffff1660e01b81526004016110119190615177565b60206040518083038186803b15801561102957600080fd5b505afa15801561103d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061047c9190810190614600565b600061098b6115c6565b6060806110766127ec565b6040805160018082528183019092529192506060919060208083019080388339019050509050755669727475616c53796e74684d6173746572636f707960501b816000815181106110c357fe5b6020026020010181815250506110d982826129dd565b9250505090565b6000546001600160a01b031681565b60045467ffffffffffffffff811690600160401b90046001600160c01b031682565b600061098b612a99565b600061098b612b01565b600080611130613f07565b61113a33866116bd565b9050611144613f07565b61114e33866116bd565b905061115a8282612bb1565b9350935050505b9250929050565b600073aa5a3d7f04e15b22eb3664b56310aa18a3527ec7638317e96b61118c6117b6565b85856111966115c6565b6040518563ffffffff1660e01b81526004016111b594939291906155ac565b60206040518083038186803b1580156111cd57600080fd5b505af41580156111e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061047991908101906145c4565b6000806000611212613f07565b61121c33876116bd565b9050611226613f07565b61123033876116bd565b905061123a613f07565b61124b33631cd554d160e21b6116bd565b905061125989848484612c26565b50939d929c50909a509098505050505050505050565b600080600061127c613f07565b61128633876116bd565b9050611290613f07565b61129a33876116bd565b9050631cd554d160e21b87148061133157506112b46127b5565b6001600160a01b0316632528f0fe886040518263ffffffff1660e01b81526004016112df919061528f565b60206040518083038186803b1580156112f757600080fd5b505afa15801561130b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061132f91908101906145c4565b155b61134d5760405162461bcd60e51b8152600401610629906153af565b631cd554d160e21b8614806113e257506113656127b5565b6001600160a01b0316632528f0fe876040518263ffffffff1660e01b8152600401611390919061528f565b60206040518083038186803b1580156113a857600080fd5b505afa1580156113bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113e091908101906145c4565b155b6113fe5760405162461bcd60e51b8152600401610629906153ff565b61140661189e565b6001600160a01b03166342a28e21886040518263ffffffff1660e01b8152600401611431919061528f565b60006040518083038186803b15801561144957600080fd5b505afa15801561145d573d6000803e3d6000fd5b5050505061146961189e565b6001600160a01b03166342a28e21876040518263ffffffff1660e01b8152600401611494919061528f565b60006040518083038186803b1580156114ac57600080fd5b505afa1580156114c0573d6000803e3d6000fd5b5050505060006114d0838361184f565b909450905080156114f35760405162461bcd60e51b8152600401610629906154bf565b60006114fd6127b5565b6001600160a01b0316638295016a8a8c8b6040518463ffffffff1660e01b815260040161152c9392919061530e565b60606040518083038186803b15801561154457600080fd5b505afa158015611558573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061157c919081019061473a565b5050905061158a8186612cfb565b965061159c818863ffffffff612d8d16565b95505050505093509350939050565b600061098b6c45786368616e6765537461746560981b612db5565b60006115d0612e12565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7077616974696e67506572696f645365637360781b6040518363ffffffff1660e01b81526004016116229291906152ab565b60206040518083038186803b15801561163a57600080fd5b505afa15801561164e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098b9190810190614600565b6000821580611690575061168c838363ffffffff6120ee16565b4210155b1561169d5750600061047c565b610479426116b1858563ffffffff6120ee16565b9063ffffffff612d8d16565b6116c5613f07565b6116cd612e2f565b6001600160a01b031663697b659b84846040518363ffffffff1660e01b81526004016116fa9291906151ae565b6101a06040518083038186803b15801561171357600080fd5b505afa158015611727573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610479919081019061465b565b600080611769836060015185606001516120ee90919063ffffffff16565b905080610479576101008084015190850151610d3c9163ffffffff6120ee16565b6000546001600160a01b031633146117b45760405162461bcd60e51b81526004016106299061548f565b565b6117be613f84565b6040518060c001604052806117d16115ab565b6001600160a01b031681526020016117e76127b5565b6001600160a01b031681526020016117fd6127d0565b6001600160a01b03168152602001611813612e55565b6001600160a01b031681526020016118296120da565b6001600160a01b0316815260200161183f6118b8565b6001600160a01b03169052905090565b60008060006118718461010001518661010001516120ee90919063ffffffff16565b9050600061187f8686612bb1565b93509050611893828263ffffffff6120ee16565b935050509250929050565b600061098b6b53797374656d53746174757360a01b612db5565b600061098b680a6f2dce8d0cae8d2f60bb1b612db5565b6000806000806000806118e0613f07565b6118ea8c8c6116bd565b90506118f4613f07565b6118fe8d8b6116bd565b905061190b8c8b8d612e6c565b611922575060009650869550611f60945050505050565b61192a6127b5565b6001600160a01b031663fce132f9836040518263ffffffff1660e01b8152600401611955919061551f565b60206040518083038186803b15801561196d57600080fd5b505afa158015611981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119a591908101906145c4565b156119c25760405162461bcd60e51b8152600401610629906154ff565b6119ca6127b5565b6001600160a01b031663fce132f9826040518263ffffffff1660e01b81526004016119f5919061551f565b60206040518083038186803b158015611a0d57600080fd5b505afa158015611a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a4591908101906145c4565b15611a625760405162461bcd60e51b81526004016106299061547f565b611a6d8b8e8e61304e565b955085611a87575060009650869550611f60945050505050565b611a8f613f07565b611aa08e631cd554d160e21b6116bd565b90506000611ab088858585612c26565b949e50929c509099509097509095509050611ac96127d0565b6001600160a01b03166378cb51cb82611ae88d8d63ffffffff6120ee16565b6040518363ffffffff1660e01b8152600401611b059291906152ab565b60206040518083038186803b158015611b1d57600080fd5b505afa158015611b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b5591908101906145c4565b15611b725760405162461bcd60e51b81526004016106299061540f565b6000631cd554d160e21b8f1415611b8a575087611bcf565b631cd554d160e21b8d1415611ba0575080611bcf565b600080611baf8b888788612c26565b5050505091509150611bca81836120ee90919063ffffffff16565b925050505b611bd98582613118565b5050505050611bee8a8c868b8a8c60006131b6565b508415611e4b57611bfd6127b5565b6001600160a01b031663654a60ac8987631cd554d160e21b6040518463ffffffff1660e01b8152600401611c339392919061530e565b60206040518083038186803b158015611c4b57600080fd5b505afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c839190810190614600565b9450611c8d6120da565b6001600160a01b03166332608039631cd554d160e21b6040518263ffffffff1660e01b8152600401611cbf919061528f565b60206040518083038186803b158015611cd757600080fd5b505afa158015611ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d0f919081019061463d565b6001600160a01b031663867904b4611d2561347e565b6001600160a01b031663eb1edd616040518163ffffffff1660e01b815260040160206040518083038186803b158015611d5d57600080fd5b505afa158015611d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d95919081019061434c565b876040518363ffffffff1660e01b8152600401611db39291906151ae565b600060405180830381600087803b158015611dcd57600080fd5b505af1158015611de1573d6000803e3d6000fd5b50505050611ded61347e565b6001600160a01b03166322bf55ef866040518263ffffffff1660e01b8152600401611e18919061528f565b600060405180830381600087803b158015611e3257600080fd5b505af1158015611e46573d6000803e3d6000fd5b505050505b611e7d60405180604001604052808c81526020018a815250604051806040016040528085815260200184815250613493565b611e856118b8565b6001600160a01b0316636c00f3108c8c878c8b8d6040518763ffffffff1660e01b8152600401611eba969594939291906151f1565b600060405180830381600087803b158015611ed457600080fd5b505af1158015611ee8573d6000803e3d6000fd5b50505050611ef46118b8565b6001600160a01b0316632f7206ce8c8c878c8b8d6040518763ffffffff1660e01b8152600401611f29969594939291906151f1565b600060405180830381600087803b158015611f4357600080fd5b505af1158015611f57573d6000803e3d6000fd5b50505050505050505b9550959350505050565b600082118015611f8257506001600160a01b03811615155b8015611f915750611f91612b01565b15610eba57611f9e6136d9565b6001600160a01b03166321cad77483836040518363ffffffff1660e01b8152600401611fcb92919061529d565b600060405180830381600087803b158015611fe557600080fd5b505af1158015611ff9573d6000803e3d6000fd5b505050505050565b6120096118b8565b6001600160a01b0316632d3169eb858585856040518563ffffffff1660e01b815260040161203a94939291906152b9565b600060405180830381600087803b15801561205457600080fd5b505af1158015612068573d6000803e3d6000fd5b5050505050505050565b600061207c612e12565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f7072696365446576696174696f6e5468726573686f6c64466163746f720000006040518363ffffffff1660e01b81526004016116229291906152ab565b600061098b6524b9b9bab2b960d11b612db5565b6000828201838110156104795760405162461bcd60e51b8152600401610629906153ef565b600061098b7044656c6567617465417070726f76616c7360781b612db5565b600080600061214a8860000151876000015189612e6c565b61215c575060009150819050806127a9565b612164613fb9565b61216c613f84565b6121746117b6565b60208101518b51604051633d00c50f60e11b81529293506001600160a01b0390911691637a018a1e916121a99160040161528f565b60206040518083038186803b1580156121c157600080fd5b505afa1580156121d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506121f99190810190614600565b60a083015260208101518851604051633d00c50f60e11b81526001600160a01b0390921691637a018a1e916122309160040161528f565b60206040518083038186803b15801561224857600080fd5b505afa15801561225c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122809190810190614600565b60c08301528951612294908a908d9061304e565b60e083018190526122b15750600093508392508291506127a99050565b60208101518a5160e08401518a5160a086015160c087015160405162d9ccd960e71b81526001600160a01b0390961695636ce66c80956122fb95909490939092909160040161531c565b60606040518083038186803b15801561231357600080fd5b505afa158015612327573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061234b919081019061473a565b6020850152835260408301528951885160a084015160c0850151612371939291906136f5565b60006123878b8a8560a001518660c00151613861565b6060850191909152905080156123aa5750600094508493508392506127a9915050565b6123bc83604001518460600151612cfb565b60408401519096506123d4908763ffffffff612d8d16565b94506123f18b600001518d8560e001518c600001518a8d8d6131b6565b93506001600160a01b03841615612406578397505b84156126615760208201518951604051631952982b60e21b81526001600160a01b039092169163654a60ac91612449918990631cd554d160e21b9060040161530e565b60206040518083038186803b15801561246157600080fd5b505afa158015612475573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124999190810190614600565b94506124a36120da565b6001600160a01b03166332608039631cd554d160e21b6040518263ffffffff1660e01b81526004016124d5919061528f565b60206040518083038186803b1580156124ed57600080fd5b505afa158015612501573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612525919081019061463d565b6001600160a01b031663867904b461253b61347e565b6001600160a01b031663eb1edd616040518163ffffffff1660e01b815260040160206040518083038186803b15801561257357600080fd5b505afa158015612587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125ab919081019061434c565b876040518363ffffffff1660e01b81526004016125c99291906151ae565b600060405180830381600087803b1580156125e357600080fd5b505af11580156125f7573d6000803e3d6000fd5b5050505061260361347e565b6001600160a01b03166322bf55ef866040518263ffffffff1660e01b815260040161262e919061528f565b600060405180830381600087803b15801561264857600080fd5b505af115801561265c573d6000803e3d6000fd5b505050505b6040805180820182528c5181528a51602080830191909152825180840190935285518352858101519083015261269691613493565b61269e6118b8565b6001600160a01b0316636c00f3108d8d600001518660e001518d600001518b8e6040518763ffffffff1660e01b81526004016126df969594939291906151f1565b600060405180830381600087803b1580156126f957600080fd5b505af115801561270d573d6000803e3d6000fd5b50505050600061271b6115c6565b11156127a55773aa5a3d7f04e15b22eb3664b56310aa18a3527ec7632f2de902838a8e600001518760e001518e600001518c8a606001516040518863ffffffff1660e01b815260040161277497969594939291906155e3565b60006040518083038186803b15801561278c57600080fd5b505af41580156127a0573d6000803e3d6000fd5b505050505b5050505b96509650969350505050565b600061098b6c45786368616e6765526174657360981b612db5565b600061098b6d21b4b931bab4ba213932b0b5b2b960911b612db5565b6060806127f76138b4565b60408051600b80825261018082019092529192506060919060208201610160803883390190505090506b53797374656d53746174757360a01b8160008151811061283d57fe5b6020026020010181815250506c45786368616e6765537461746560981b8160018151811061286757fe5b6020026020010181815250506c45786368616e6765526174657360981b8160028151811061289157fe5b602002602001018181525050680a6f2dce8d0cae8d2f60bb1b816003815181106128b757fe5b60200260200101818152505066119959541bdbdb60ca1b816004815181106128db57fe5b6020026020010181815250506d54726164696e675265776172647360901b8160058151811061290657fe5b6020026020010181815250507044656c6567617465417070726f76616c7360781b8160068151811061293457fe5b6020026020010181815250506524b9b9bab2b960d11b8160078151811061295757fe5b6020026020010181815250506844656274436163686560b81b8160088151811061297d57fe5b6020026020010181815250506d21b4b931bab4ba213932b0b5b2b960911b816009815181106129a857fe5b602002602001018181525050772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b81600a815181106110c357fe5b60608151835101604051908082528060200260200182016040528015612a0d578160200160208202803883390190505b50905060005b8351811015612a4f57838181518110612a2857fe5b6020026020010151828281518110612a3c57fe5b6020908102919091010152600101612a13565b5060005b8251811015612a9257828181518110612a6857fe5b6020026020010151828286510181518110612a7f57fe5b6020908102919091010152600101612a53565b5092915050565b6000612aa3612e12565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f61746f6d69634d6178566f6c756d65506572426c6f636b0000000000000000006040518363ffffffff1660e01b81526004016116229291906152ab565b6000612b0b612e12565b6001600160a01b031663d994502d6d53797374656d53657474696e677360901b741d1c98591a5b99d4995dd85c991cd15b98589b1959605a1b6040518363ffffffff1660e01b8152600401612b619291906152ab565b60206040518083038186803b158015612b7957600080fd5b505afa158015612b8d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098b91908101906145c4565b600080600080612bc085613905565b91509150600080612bd088613905565b9092509050612be5848363ffffffff6120ee16565b610120890151909650861180612bfb5786612c02565b8861012001515b9650868180612c0e5750845b80612c165750825b9650965050505050509250929050565b6000806000806000806000612c396127b5565b6001600160a01b03166326bd30fa8b8d8c8c6040518563ffffffff1660e01b8152600401612c6a949392919061552e565b60806040518083038186803b158015612c8257600080fd5b505afa158015612c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cba91908101906147ea565b919650945092509050612ccd8a8a61174b565b9450612cd98186612cfb565b9650612ceb818863ffffffff612d8d16565b9550509499939850945094509450565b6000610479612d80837384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4857600080fd5b505af4158015612d5c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b19190810190614600565b849063ffffffff6139d616565b600082821115612daf5760405162461bcd60e51b81526004016106299061542f565b50900390565b60008181526003602090815260408083205490516001600160a01b039091169182151591612de59186910161514c565b60405160208183030381529060405290612a925760405162461bcd60e51b8152600401610629919061539e565b600061098b6e466c657869626c6553746f7261676560881b612db5565b600061098b772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b612db5565b600061098b6844656274436163686560b81b612db5565b600082841415612e8e5760405162461bcd60e51b8152600401610629906153bf565b60008211612eae5760405162461bcd60e51b81526004016106299061541f565b600080631cd554d160e21b861415612ec95760008080612f4e565b612ed16127b5565b6001600160a01b031663045056f8876040518263ffffffff1660e01b8152600401612efc919061528f565b606060405180830381600087803b158015612f1657600080fd5b505af1158015612f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f4e91908101906146aa565b9250925050600080631cd554d160e21b871415612f6e5760008080612ff3565b612f766127b5565b6001600160a01b031663045056f8886040518263ffffffff1660e01b8152600401612fa1919061528f565b606060405180830381600087803b158015612fbb57600080fd5b505af1158015612fcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612ff391908101906146aa565b925092505082156130165760405162461bcd60e51b8152600401610629906154df565b80156130345760405162461bcd60e51b81526004016106299061544f565b83158015613040575081155b9450505050505b9392505050565b600080600073aa5a3d7f04e15b22eb3664b56310aa18a3527ec76377cd29a56130756117b6565b878760006130816115c6565b6040518663ffffffff1660e01b81526004016130a1959493929190615567565b60606040518083038186803b1580156130b957600080fd5b505af41580156130cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130f1919081019061473a565b889550909350915050801561310f5761310c85858885610990565b92505b50509392505050565b60045460009067ffffffffffffffff1642146131345781613151565b60045461315190600160401b90046001600160c01b0316836120ee565b90508260a001518111156131775760405162461bcd60e51b81526004016106299061550f565b600480546001600160c01b03909216600160401b0267ffffffffffffffff42811667ffffffffffffffff19909416939093179092169190911790555050565b60006131c06120da565b6001600160a01b03166332608039896040518263ffffffff1660e01b81526004016131eb919061528f565b60206040518083038186803b15801561320357600080fd5b505afa158015613217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061323b919081019061463d565b6001600160a01b0316639dc29fac88886040518363ffffffff1660e01b81526004016132689291906151ae565b600060405180830381600087803b15801561328257600080fd5b505af1158015613296573d6000803e3d6000fd5b5050505060006132a46120da565b6001600160a01b03166332608039876040518263ffffffff1660e01b81526004016132cf919061528f565b60206040518083038186803b1580156132e757600080fd5b505afa1580156132fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061331f919081019061463d565b905082156134115760008190506133a8816001600160a01b031663ec5568896040518163ffffffff1660e01b815260040160206040518083038186803b15801561336857600080fd5b505afa15801561337c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506133a0919081019061463d565b86888a613a00565b60405163219e412d60e21b81529093506001600160a01b0383169063867904b4906133d99086908a906004016151ae565b600060405180830381600087803b1580156133f357600080fd5b505af1158015613407573d6000803e3d6000fd5b5050505050613472565b60405163219e412d60e21b81526001600160a01b0382169063867904b49061343f90879089906004016151ae565b600060405180830381600087803b15801561345957600080fd5b505af115801561346d573d6000803e3d6000fd5b505050505b50979650505050505050565b600061098b66119959541bdbdb60ca1b612db5565b8151600090631cd554d160e21b14806134b657506020830151631cd554d160e21b145b90506000816134c65760036134c9565b60025b60ff1690506060816040519080825280602002602001820160405280156134fa578160200160208202803883390190505b50905084600060200201518160008151811061351257fe5b602090810291909101015284600160200201518160018151811061353257fe5b60200260200101818152505060608260405190808252806020026020018201604052801561356a578160200160208202803883390190505b50905084600060200201518160008151811061358257fe5b60209081029190910101528460016020020151816001815181106135a257fe5b6020026020010181815250508361366a57631cd554d160e21b826002815181106135c857fe5b6020026020010181815250507384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561361857600080fd5b505af415801561362c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506136509190810190614600565b8160028151811061365d57fe5b6020026020010181815250505b613672612e55565b6001600160a01b03166317b38db483836040518363ffffffff1660e01b815260040161369f92919061525c565b600060405180830381600087803b1580156136b957600080fd5b505af11580156136cd573d6000803e3d6000fd5b50505050505050505050565b600061098b6d54726164696e675265776172647360901b612db5565b828414156137155760405162461bcd60e51b8152600401610629906153bf565b6040805160028082526060808301845292602083019080388339019050509050848160008151811061374357fe5b602002602001018181525050838160018151811061375d57fe5b60209081029190910101526040805160028082526060828101909352816020016020820280388339019050509050838160008151811061379957fe5b60200260200101818152505082816001815181106137b357fe5b6020026020010181815250506137c76127b5565b6001600160a01b031663d89ee86183836040518363ffffffff1660e01b81526004016137f492919061525c565b60206040518083038186803b15801561380c57600080fd5b505afa158015613820573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061384491908101906145c4565b15611ff95760405162461bcd60e51b8152600401610629906154ef565b60008060006138838661010001518861010001516120ee90919063ffffffff16565b9050600061389388888888613b43565b935090506138a7828263ffffffff6120ee16565b9350505094509492505050565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b816000815181106138f657fe5b60200260200101818152505090565b600080631cd554d160e21b836000015114806139275750600183610140015111155b15613937575060009050806139d1565b60006139416127b5565b8451604051633d00c50f60e11b81526001600160a01b039290921691637a018a1e9161396f9160040161528f565b60206040518083038186803b15801561398757600080fd5b505afa15801561399b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506139bf9190810190614600565b90506139cb8482613bbc565b92509250505b915091565b6000670de0b6b3a76400006139f1848463ffffffff613cc616565b816139f857fe5b049392505050565b6000606960f81b6001600160f81b031983831a60f81b161415613a355760405162461bcd60e51b8152600401610629906154cf565b6000613a7d613a42613d00565b6040518060400160405280601b81526020017f436f756c64206e6f7420637265617465206e6577207653796e74680000000000815250613d24565b600254604051638d7017d360e01b81529192506001600160a01b0380841692638d7017d392613ab9928b929116908a908a908a90600401615376565b600060405180830381600087803b158015613ad357600080fd5b505af1158015613ae7573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b03167fb5ec76d79549c775883022e4426db5cd36bd5307f216cdb341554c301548ef9f838688604051613b32939291906151c9565b60405180910390a395945050505050565b600080600080613b538786613bbc565b91509150600080613b648a89613bbc565b9092509050613b79848363ffffffff6120ee16565b6101208b0151909650861180613b8f5786613b96565b8a61012001515b9650868180613ba25750845b80613baa5750825b96509650505050505094509492505050565b600080631cd554d160e21b84600001511480613bde5750600184610140015111155b15613bee57506000905080611161565b6060613bf86127b5565b8551610140870151604051630ed7624560e41b81526001600160a01b03939093169263ed76245092613c30929091899060040161530e565b60006040518083038186803b158015613c4857600080fd5b505afa158015613c5c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c849190810190614565565b5080915050613c9e81866101600151876101800151613d6e565b610120860151909350831180613cb45783613cbb565b8561012001515b969095509350505050565b600082613cd55750600061047c565b82820282848281613ce257fe5b04146104795760405162461bcd60e51b8152600401610629906154af565b600061098b755669727475616c53796e74684d6173746572636f707960501b612db5565b60006060613d3184613df8565b90506037602082016000f09150826001600160a01b038316613d665760405162461bcd60e51b8152600401610629919061539e565b505092915050565b6000835160001415613d8257506000613047565b8351600090600019015b8015610ab857613da2828563ffffffff6139d616565b91506000613dda876001840381518110613db857fe5b6020026020010151888481518110613dcc57fe5b602002602001015188613e54565b9050613dec838263ffffffff6120ee16565b92505060001901613d8c565b604051606090613e3e90693d602d80600a3d3981f360b01b9069363d3d373d3d3d363d7360b01b9085906e5af43d82803e903d91602b57fd5bf360881b90602001615104565b6040516020818303038152906040529050919050565b600082613e6357506000613047565b6000838511613e7457848403613e78565b8385035b90506000613e8c828663ffffffff613ea816565b9050838111613e9c57600061310c565b92909203949350505050565b600061047982613ec685670de0b6b3a764000063ffffffff613cc616565b9063ffffffff613ed216565b6000808211613ef35760405162461bcd60e51b81526004016106299061543f565b6000828481613efe57fe5b04949350505050565b604051806101a001604052806000801916815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b803561047c816157bd565b805161047c816157bd565b600082601f83011261402557600080fd5b8151614038614033826156c8565b6156a1565b915081818352602084019350602081019050838561010084028201111561405e57600080fd5b60005b8381101561408d5781614074888261413e565b8452506020909201916101009190910190600101614061565b5050505092915050565b600082601f8301126140a857600080fd5b81516140b6614033826156c8565b915081818352602084019350602081019050838560208402820111156140db57600080fd5b60005b8381101561408d57816140f18882614128565b84525060209283019291909101906001016140de565b803561047c816157d4565b805161047c816157d4565b803561047c816157dd565b805161047c816157dd565b805161047c816157e6565b6000610100828403121561415157600080fd5b61415c6101006156a1565b9050600061416a8484614128565b825250602061417b84848301614128565b602083015250604061418f84828501614128565b60408301525060606141a384828501614128565b60608301525060806141b784828501614128565b60808301525060a06141cb84828501614128565b60a08301525060c06141df84828501614128565b60c08301525060e06141f384828501614128565b60e08301525092915050565b60006101a0828403121561421257600080fd5b61421d6101a06156a1565b9050600061422b8484614128565b825250602061423c84848301614009565b602083015250604061425084828501614009565b604083015250606061426484828501614128565b606083015250608061427884828501614128565b60808301525060a061428c84828501614128565b60a08301525060c06142a084828501614128565b60c08301525060e06142b484828501614128565b60e0830152506101006142c984828501614128565b610100830152506101206142df84828501614128565b610120830152506101406142f584828501614128565b6101408301525061016061430b84828501614128565b6101608301525061018061432184828501614128565b6101808301525092915050565b60006020828403121561434057600080fd5b6000610d3c8484613ffe565b60006020828403121561435e57600080fd5b6000610d3c8484614009565b60008060008060008060008060006101208a8c03121561438957600080fd5b60006143958c8c613ffe565b99505060206143a68c828d01613ffe565b98505060406143b78c828d0161411d565b97505060606143c88c828d0161411d565b96505060806143d98c828d0161411d565b95505060a06143ea8c828d01613ffe565b94505060c06143fb8c828d01614107565b93505060e061440c8c828d01613ffe565b92505061010061441e8c828d0161411d565b9150509295985092959850929598565b6000806040838503121561444157600080fd5b600061444d8585613ffe565b925050602061445e8582860161411d565b9150509250929050565b600080600080600080600060e0888a03121561448357600080fd5b600061448f8a8a613ffe565b97505060206144a08a828b0161411d565b96505060406144b18a828b0161411d565b95505060606144c28a828b0161411d565b94505060806144d38a828b01613ffe565b93505060a06144e48a828b0161411d565b92505060c06144f58a828b0161411d565b91505092959891949750929550565b6000806000806080858703121561451a57600080fd5b60006145268787613ffe565b94505060206145378782880161411d565b93505060406145488782880161411d565b92505060606145598782880161411d565b91505092959194509250565b6000806040838503121561457857600080fd5b825167ffffffffffffffff81111561458f57600080fd5b61459b85828601614097565b925050602083015167ffffffffffffffff8111156145b857600080fd5b61445e85828601614097565b6000602082840312156145d657600080fd5b6000610d3c8484614112565b6000602082840312156145f457600080fd5b6000610d3c848461411d565b60006020828403121561461257600080fd5b6000610d3c8484614128565b6000806040838503121561463157600080fd5b600061444d858561411d565b60006020828403121561464f57600080fd5b6000610d3c8484614133565b60006101a0828403121561466e57600080fd5b6000610d3c84846141ff565b6000806040838503121561468d57600080fd5b60006146998585614128565b925050602061445e85828601614112565b6000806000606084860312156146bf57600080fd5b60006146cb8686614128565b93505060206146dc86828701614112565b92505060406146ed86828701614112565b9150509250925092565b60008060006060848603121561470c57600080fd5b6000614718868661411d565b93505060206147298682870161411d565b92505060406146ed8682870161411d565b60008060006060848603121561474f57600080fd5b600061475b8686614128565b935050602061476c86828701614128565b92505060406146ed86828701614128565b6000806000806080858703121561479357600080fd5b600061479f8787614128565b94505060206147b087828801614128565b93505060406147c187828801614128565b925050606085015167ffffffffffffffff8111156147de57600080fd5b61455987828801614014565b6000806000806080858703121561480057600080fd5b600061480c8787614128565b945050602061481d87828801614128565b935050604061482e87828801614128565b925050606061455987828801614128565b600061484b8383614949565b505060200190565b61485c81615765565b82525050565b61485c81615701565b61485c61487782615701565b61579c565b6000614887826156ef565b61489181856156f3565b935061489c836156e9565b8060005b838110156148ca5781516148b4888261483f565b97506148bf836156e9565b9250506001016148a0565b509495945050505050565b60006148e0826156ef565b6148ea81856156f3565b93506148f5836156e9565b8060005b838110156148ca57815161490d888261483f565b9750614918836156e9565b9250506001016148f9565b61485c8161570c565b61485c61493882615711565b610864565b61485c6149388261571e565b61485c81610864565b61485c61493882610864565b61485c81615735565b6000614972826156ef565b61497c81856156f3565b935061498c818560208601615770565b614995816157ad565b9093019392505050565b60006149ac6016836156f3565b751cdc98c81cde5b9d1a081c985d19481a5b9d985b1a5960521b815260200192915050565b60006149de6013836156f3565b72086c2dc4ee840c4ca40e6c2daca40e6f2dce8d606b1b815260200192915050565b6000614a0d6035836156f3565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b6000614a64601d836156f3565b7f4e6f7420617070726f76656420746f20616374206f6e20626568616c66000000815260200192915050565b6000614a9d601b836156f3565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000614ad66017836156f3565b7f646573742073796e7468207261746520696e76616c6964000000000000000000815260200192915050565b6000614b0f601d836156f3565b7f41746f6d6963207261746520646576696174657320746f6f206d756368000000815260200192915050565b6000614b48600b836156f3565b6a16995c9bc8185b5bdd5b9d60aa1b815260200192915050565b6000614b6f601e836156f3565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000614ba8601a836156f3565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b6000614be16011836156fc565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b6000614c0e601a836156f3565b7f646573742072617465207374616c65206f7220666c6167676564000000000000815260200192915050565b6000614c47603a836156f3565b7f54686520616d6f756e742072656365697665642069732062656c6f772074686581527f206d696e696d756d20616d6f756e74207370656369666965642e000000000000602082015260400192915050565b6000614ca66045836156f3565b7f45786368616e6765723a204f6e6c792073796e746865746978206f722061207381527f796e746820636f6e74726163742063616e20706572666f726d2074686973206160208201526431ba34b7b760d91b604082015260600192915050565b6000614d136017836156f3565b7f446573742073796e746820746f6f20766f6c6174696c65000000000000000000815260200192915050565b6000614d4c602f836156f3565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b6000614d9d600c836156f3565b6b746f6f20766f6c6174696c6560a01b815260200192915050565b6000614dc56021836156f3565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614e08601b836156f3565b7f65786368616e676520726174657320746f6f20766f6c6174696c650000000000815260200192915050565b6000614e41601c836156f3565b7f43616e6e6f74207669727475616c697a6520746869732073796e746800000000815260200192915050565b6000614e7a6019836156fc565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000614eb36019836156f3565b7f7372632072617465207374616c65206f7220666c616767656400000000000000815260200192915050565b6000614eec601e836156f3565b7f7372632f646573742072617465207374616c65206f7220666c61676765640000815260200192915050565b6000614f256016836156f3565b755372632073796e746820746f6f20766f6c6174696c6560501b815260200192915050565b6000614f576016836156f3565b7514dd5c9c185cdcd959081d9bdb1d5b59481b1a5b5a5d60521b815260200192915050565b80516101a0830190614f8e8482614949565b506020820151614fa16020850182614862565b506040820151614fb46040850182614862565b506060820151614fc76060850182614949565b506080820151614fda6080850182614949565b5060a0820151614fed60a0850182614949565b5060c082015161500060c0850182614949565b5060e082015161501360e0850182614949565b50610100820151615028610100850182614949565b5061012082015161503d610120850182614949565b50610140820151615052610140850182614949565b50610160820151615067610160850182614949565b5061018082015161507c610180850182614949565b50505050565b805160c0830190615093848261495e565b5060208201516150a6602085018261495e565b5060408201516150b9604085018261495e565b5060608201516150cc606085018261495e565b5060808201516150df608085018261495e565b5060a082015161507c60a085018261495e565b61485c8161574c565b61485c81615758565b6000615110828761492c565b600a82019150615120828661492c565b600a82019150615130828561486b565b601482019150615140828461493d565b50600f01949350505050565b600061515782614bd4565b91506151638284614952565b50602001919050565b600061515782614e6d565b6020810161047c8284614862565b6020810161047c8284614853565b604081016151a18285614862565b6130476020830184614862565b604081016151bc8285614862565b6130476020830184614949565b606081016151d78286614862565b6151e46020830185614949565b610d3c6040830184614949565b60c081016151ff8289614862565b61520c6020830188614949565b6152196040830187614949565b6152266060830186614949565b6152336080830185614949565b61524060a0830184614862565b979650505050505050565b60208082528101610479818461487c565b6040808252810161526d818561487c565b90508181036020830152610d3c81846148d5565b6020810161047c8284614923565b6020810161047c8284614949565b604081016151a18285614949565b604081016151bc8285614949565b608081016152c78287614949565b6152d46020830186614949565b6152e16040830185614949565b6104b66060830184614949565b604081016152fc8285614949565b8181036020830152610d3c8184614967565b606081016151d78286614949565b60a0810161532a8288614949565b6153376020830187614949565b6153446040830186614949565b6153516060830185614949565b61535e6080830184614949565b9695505050505050565b6020810161047c828461495e565b60a08101615384828861495e565b615391602083018761495e565b6153446040830186614862565b602080825281016104798184614967565b6020808252810161047c8161499f565b6020808252810161047c816149d1565b6020808252810161047c81614a00565b6020808252810161047c81614a57565b6020808252810161047c81614a90565b6020808252810161047c81614ac9565b6020808252810161047c81614b02565b6020808252810161047c81614b3b565b6020808252810161047c81614b62565b6020808252810161047c81614b9b565b6020808252810161047c81614c01565b6020808252810161047c81614c3a565b6020808252810161047c81614c99565b6020808252810161047c81614d06565b6020808252810161047c81614d3f565b6020808252810161047c81614d90565b6020808252810161047c81614db8565b6020808252810161047c81614dfb565b6020808252810161047c81614e34565b6020808252810161047c81614ea6565b6020808252810161047c81614edf565b6020808252810161047c81614f18565b6020808252810161047c81614f4a565b6101a0810161047c8284614f7c565b610500810161553d8287614f7c565b61554b6101a0830186614949565b6155596101c0830185614f7c565b6104b6610360830184614f7c565b61014081016155768288615082565b61558360c0830187614862565b61559060e0830186614949565b61559e610100830185614923565b61535e610120830184614949565b61012081016155bb8287615082565b6155c860c0830186614862565b6155d560e0830185614949565b6104b6610100830184614949565b61018081016155f2828a615082565b6155ff60c0830189614862565b61560c60e0830188614949565b61561a610100830187614949565b615628610120830186614949565b615636610140830185614949565b615644610160830184614949565b98975050505050505050565b6040810161565e8285614949565b6130476020830184614923565b604081016156798285614949565b613047602083018461495e565b6040810161569482856150fb565b61304760208301846150f2565b60405181810167ffffffffffffffff811182821017156156c057600080fd5b604052919050565b600067ffffffffffffffff8211156156df57600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b919050565b600061047c82615740565b151590565b6001600160b01b03191690565b70ffffffffffffffffffffffffffffffffff191690565b600061047c82615701565b6001600160a01b031690565b6001600160c01b031690565b67ffffffffffffffff1690565b600061047c82615735565b60005b8381101561578b578181015183820152602001615773565b8381111561507c5750506000910152565b600061047c82600061047c826157b7565b601f01601f191690565b60601b90565b6157c681615701565b81146157d157600080fd5b50565b6157c68161570c565b6157c681610864565b6157c68161573556fea365627a7a72315820577fb23de8a6037dcd49350690073c896549aae5811f541f95c21022701d053b6c6578706572696d656e74616cf564736f6c63430005100040000000000000000000000000302d2451d9f47620374b54c521423bf0403916a20000000000000000000000004e3b31eb0e5cb73641ee1e65e7dcefe520ba3ef2
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101c45760003560e01c8063614d08f8116100f95780638e52049c11610097578063c39def0b11610071578063c39def0b14610379578063d6f32e061461039a578063dc703e73146103ad578063f450aa34146103c0576101c4565b80638e52049c14610353578063a4bca13114610369578063c193f0d814610371576101c4565b80637dd1a57a116100d35780637dd1a57a1461031b578063892571171461032e578063899ffef4146103365780638da5cb5b1461034b576101c4565b8063614d08f814610303578063741853601461030b57806379ba509714610313576101c4565b80632af64bd3116101665780634c268fc8116101405780634c268fc8146102a75780634f8633d2146102ba57806353a47bb7146102db57806357af302c146102f0576101c4565b80632af64bd31461027757806333a768801461028c578063372a395a1461029f576101c4565b80631627540c116101a25780631627540c1461021a57806319d5c6651461022f5780631a5c6095146102515780631b16802c14610264576101c4565b806304f3bcec146101c9578063059c29ec146101e75780630ae81a5e14610207575b600080fd5b6101d16103d3565b6040516101de9190615368565b60405180910390f35b6101fa6101f536600461442e565b6103e2565b6040516101de919061528f565b6101fa61021536600461461e565b610482565b61022d61022836600461432e565b6104bf565b005b61024261023d36600461442e565b61051d565b6040516101de9392919061530e565b6101fa61025f36600461461e565b6105d0565b61024261027236600461442e565b61063c565b61027f61074f565b6040516101de9190615281565b6101fa61029a366004614468565b610867565b6101fa610981565b6101fa6102b5366004614504565b610990565b6102cd6102c836600461436a565b610ac1565b6040516101de92919061566b565b6102e3610ca8565b6040516101de9190615177565b61027f6102fe3660046145e2565b610cb7565b6101fa610d44565b61022d610d68565b61022d610ebe565b6101fa6103293660046145e2565b610f5a565b6101fa611061565b61033e61106b565b6040516101de919061524b565b6102e36110e0565b61035b6110ef565b6040516101de929190615686565b6101fa611111565b61027f61111b565b61038c61038736600461461e565b611125565b6040516101de929190615650565b61027f6103a836600461442e565b611168565b6102426103bb3660046146f7565b611205565b6102426103ce3660046146f7565b61126f565b6002546001600160a01b031681565b60006104796103ef6115ab565b6001600160a01b031663f1406dc885856040518363ffffffff1660e01b815260040161041c9291906151ae565b60206040518083038186803b15801561043457600080fd5b505afa158015610448573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061046c9190810190614600565b6104746115c6565b611672565b90505b92915050565b600061048c613f07565b61049633856116bd565b90506104a0613f07565b6104aa33856116bd565b90506104b6828261174b565b95945050505050565b6104c761178a565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290610512908390615177565b60405180910390a150565b600080600073aa5a3d7f04e15b22eb3664b56310aa18a3527ec7630a0ecd1b6105446117b6565b878761054e6115c6565b6040518563ffffffff1660e01b815260040161056d94939291906155ac565b60006040518083038186803b15801561058557600080fd5b505af4158015610599573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105c1919081019061477d565b50919790965090945092505050565b60006105da613f07565b6105e433856116bd565b90506105ee613f07565b6105f833856116bd565b9050600080610607848461184f565b9150915080156106325760405162461bcd60e51b81526004016106299061549f565b60405180910390fd5b5095945050505050565b600080600061064961189e565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b8152600401610674919061528f565b60006040518083038186803b15801561068c57600080fd5b505afa1580156106a0573d6000803e3d6000fd5b5050505073aa5a3d7f04e15b22eb3664b56310aa18a3527ec76377cd29a56106c66117b6565b878760016106d26115c6565b6040518663ffffffff1660e01b81526004016106f2959493929190615567565b60606040518083038186803b15801561070a57600080fd5b505af415801561071e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610742919081019061473a565b9250925092509250925092565b6000606061075b61106b565b905060005b815181101561085d57600082828151811061077757fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a721906107c890859060040161528f565b60206040518083038186803b1580156107e057600080fd5b505afa1580156107f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610818919081019061434c565b6001600160a01b031614158061084357506000818152600360205260409020546001600160a01b0316155b156108545760009350505050610864565b50600101610760565b5060019150505b90565b6000806108726118b8565b9050336001600160a01b038216148061090857506040516316b2213f60e01b81526000906001600160a01b038316906316b2213f906108b5903390600401615185565b60206040518083038186803b1580156108cd57600080fd5b505afa1580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109059190810190614600565b14155b6109245760405162461bcd60e51b81526004016106299061546f565b60006109338a8a8a8a8a6118cf565b9093509050838310156109585760405162461bcd60e51b81526004016106299061545f565b6109628187611f6a565b84156109745761097485888584612001565b5050979650505050505050565b600061098b612072565b905090565b81600061099b6120da565b6001600160a01b03166332608039866040518263ffffffff1660e01b81526004016109c6919061528f565b60206040518083038186803b1580156109de57600080fd5b505afa1580156109f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a16919081019061463d565b6001600160a01b03166370a08231876040518263ffffffff1660e01b8152600401610a419190615177565b60206040518083038186803b158015610a5957600080fd5b505afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a919190810190614600565b905080821115610a9f578091505b8215610ab857610ab5828463ffffffff6120ee16565b91505b50949350505050565b6000806000610ace6118b8565b9050336001600160a01b0382161480610b6457506040516316b2213f60e01b81526000906001600160a01b038316906316b2213f90610b11903390600401615185565b60206040518083038186803b158015610b2957600080fd5b505afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b619190810190614600565b14155b610b805760405162461bcd60e51b81526004016106299061546f565b60008c6001600160a01b03168c6001600160a01b031614610c3c57610ba3612113565b6001600160a01b031663faf431bb8e8e6040518363ffffffff1660e01b8152600401610bd0929190615193565b60206040518083038186803b158015610be857600080fd5b505afa158015610bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c2091908101906145c4565b610c3c5760405162461bcd60e51b8152600401610629906153df565b610c44613f07565b610c4e8d8d6116bd565b9050610c58613f07565b610c628e8c6116bd565b9050610c728f838e848e8e612132565b9197509095509250610c848389611f6a565b8615610c9657610c96878c8886612001565b50505050995099975050505050505050565b6001546001600160a01b031681565b600080610cc26127b5565b6001600160a01b0316630c71cd23846040518263ffffffff1660e01b8152600401610ced919061528f565b604080518083038186803b158015610d0457600080fd5b505afa158015610d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3c919081019061467a565b949350505050565b7f45786368616e67657257697468466565526563416c7465726e6174697665730081565b6060610d7261106b565b905060005b8151811015610eba576000828281518110610d8e57fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610dd0919061516c565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610dfc9291906152ee565b60206040518083038186803b158015610e1457600080fd5b505afa158015610e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4c919081019061434c565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa6890610ea8908490849061529d565b60405180910390a15050600101610d77565b5050565b6001546001600160a01b03163314610ee85760405162461bcd60e51b8152600401610629906153cf565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c92610f2b926001600160a01b0391821692911690615193565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000610f646127d0565b6001600160a01b031663ba03e93f610f7a6127b5565b6001600160a01b0316637103353e856040518263ffffffff1660e01b8152600401610fa5919061528f565b60206040518083038186803b158015610fbd57600080fd5b505afa158015610fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ff5919081019061434c565b6040518263ffffffff1660e01b81526004016110119190615177565b60206040518083038186803b15801561102957600080fd5b505afa15801561103d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061047c9190810190614600565b600061098b6115c6565b6060806110766127ec565b6040805160018082528183019092529192506060919060208083019080388339019050509050755669727475616c53796e74684d6173746572636f707960501b816000815181106110c357fe5b6020026020010181815250506110d982826129dd565b9250505090565b6000546001600160a01b031681565b60045467ffffffffffffffff811690600160401b90046001600160c01b031682565b600061098b612a99565b600061098b612b01565b600080611130613f07565b61113a33866116bd565b9050611144613f07565b61114e33866116bd565b905061115a8282612bb1565b9350935050505b9250929050565b600073aa5a3d7f04e15b22eb3664b56310aa18a3527ec7638317e96b61118c6117b6565b85856111966115c6565b6040518563ffffffff1660e01b81526004016111b594939291906155ac565b60206040518083038186803b1580156111cd57600080fd5b505af41580156111e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061047991908101906145c4565b6000806000611212613f07565b61121c33876116bd565b9050611226613f07565b61123033876116bd565b905061123a613f07565b61124b33631cd554d160e21b6116bd565b905061125989848484612c26565b50939d929c50909a509098505050505050505050565b600080600061127c613f07565b61128633876116bd565b9050611290613f07565b61129a33876116bd565b9050631cd554d160e21b87148061133157506112b46127b5565b6001600160a01b0316632528f0fe886040518263ffffffff1660e01b81526004016112df919061528f565b60206040518083038186803b1580156112f757600080fd5b505afa15801561130b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061132f91908101906145c4565b155b61134d5760405162461bcd60e51b8152600401610629906153af565b631cd554d160e21b8614806113e257506113656127b5565b6001600160a01b0316632528f0fe876040518263ffffffff1660e01b8152600401611390919061528f565b60206040518083038186803b1580156113a857600080fd5b505afa1580156113bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113e091908101906145c4565b155b6113fe5760405162461bcd60e51b8152600401610629906153ff565b61140661189e565b6001600160a01b03166342a28e21886040518263ffffffff1660e01b8152600401611431919061528f565b60006040518083038186803b15801561144957600080fd5b505afa15801561145d573d6000803e3d6000fd5b5050505061146961189e565b6001600160a01b03166342a28e21876040518263ffffffff1660e01b8152600401611494919061528f565b60006040518083038186803b1580156114ac57600080fd5b505afa1580156114c0573d6000803e3d6000fd5b5050505060006114d0838361184f565b909450905080156114f35760405162461bcd60e51b8152600401610629906154bf565b60006114fd6127b5565b6001600160a01b0316638295016a8a8c8b6040518463ffffffff1660e01b815260040161152c9392919061530e565b60606040518083038186803b15801561154457600080fd5b505afa158015611558573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061157c919081019061473a565b5050905061158a8186612cfb565b965061159c818863ffffffff612d8d16565b95505050505093509350939050565b600061098b6c45786368616e6765537461746560981b612db5565b60006115d0612e12565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7077616974696e67506572696f645365637360781b6040518363ffffffff1660e01b81526004016116229291906152ab565b60206040518083038186803b15801561163a57600080fd5b505afa15801561164e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098b9190810190614600565b6000821580611690575061168c838363ffffffff6120ee16565b4210155b1561169d5750600061047c565b610479426116b1858563ffffffff6120ee16565b9063ffffffff612d8d16565b6116c5613f07565b6116cd612e2f565b6001600160a01b031663697b659b84846040518363ffffffff1660e01b81526004016116fa9291906151ae565b6101a06040518083038186803b15801561171357600080fd5b505afa158015611727573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610479919081019061465b565b600080611769836060015185606001516120ee90919063ffffffff16565b905080610479576101008084015190850151610d3c9163ffffffff6120ee16565b6000546001600160a01b031633146117b45760405162461bcd60e51b81526004016106299061548f565b565b6117be613f84565b6040518060c001604052806117d16115ab565b6001600160a01b031681526020016117e76127b5565b6001600160a01b031681526020016117fd6127d0565b6001600160a01b03168152602001611813612e55565b6001600160a01b031681526020016118296120da565b6001600160a01b0316815260200161183f6118b8565b6001600160a01b03169052905090565b60008060006118718461010001518661010001516120ee90919063ffffffff16565b9050600061187f8686612bb1565b93509050611893828263ffffffff6120ee16565b935050509250929050565b600061098b6b53797374656d53746174757360a01b612db5565b600061098b680a6f2dce8d0cae8d2f60bb1b612db5565b6000806000806000806118e0613f07565b6118ea8c8c6116bd565b90506118f4613f07565b6118fe8d8b6116bd565b905061190b8c8b8d612e6c565b611922575060009650869550611f60945050505050565b61192a6127b5565b6001600160a01b031663fce132f9836040518263ffffffff1660e01b8152600401611955919061551f565b60206040518083038186803b15801561196d57600080fd5b505afa158015611981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506119a591908101906145c4565b156119c25760405162461bcd60e51b8152600401610629906154ff565b6119ca6127b5565b6001600160a01b031663fce132f9826040518263ffffffff1660e01b81526004016119f5919061551f565b60206040518083038186803b158015611a0d57600080fd5b505afa158015611a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a4591908101906145c4565b15611a625760405162461bcd60e51b81526004016106299061547f565b611a6d8b8e8e61304e565b955085611a87575060009650869550611f60945050505050565b611a8f613f07565b611aa08e631cd554d160e21b6116bd565b90506000611ab088858585612c26565b949e50929c509099509097509095509050611ac96127d0565b6001600160a01b03166378cb51cb82611ae88d8d63ffffffff6120ee16565b6040518363ffffffff1660e01b8152600401611b059291906152ab565b60206040518083038186803b158015611b1d57600080fd5b505afa158015611b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b5591908101906145c4565b15611b725760405162461bcd60e51b81526004016106299061540f565b6000631cd554d160e21b8f1415611b8a575087611bcf565b631cd554d160e21b8d1415611ba0575080611bcf565b600080611baf8b888788612c26565b5050505091509150611bca81836120ee90919063ffffffff16565b925050505b611bd98582613118565b5050505050611bee8a8c868b8a8c60006131b6565b508415611e4b57611bfd6127b5565b6001600160a01b031663654a60ac8987631cd554d160e21b6040518463ffffffff1660e01b8152600401611c339392919061530e565b60206040518083038186803b158015611c4b57600080fd5b505afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c839190810190614600565b9450611c8d6120da565b6001600160a01b03166332608039631cd554d160e21b6040518263ffffffff1660e01b8152600401611cbf919061528f565b60206040518083038186803b158015611cd757600080fd5b505afa158015611ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d0f919081019061463d565b6001600160a01b031663867904b4611d2561347e565b6001600160a01b031663eb1edd616040518163ffffffff1660e01b815260040160206040518083038186803b158015611d5d57600080fd5b505afa158015611d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d95919081019061434c565b876040518363ffffffff1660e01b8152600401611db39291906151ae565b600060405180830381600087803b158015611dcd57600080fd5b505af1158015611de1573d6000803e3d6000fd5b50505050611ded61347e565b6001600160a01b03166322bf55ef866040518263ffffffff1660e01b8152600401611e18919061528f565b600060405180830381600087803b158015611e3257600080fd5b505af1158015611e46573d6000803e3d6000fd5b505050505b611e7d60405180604001604052808c81526020018a815250604051806040016040528085815260200184815250613493565b611e856118b8565b6001600160a01b0316636c00f3108c8c878c8b8d6040518763ffffffff1660e01b8152600401611eba969594939291906151f1565b600060405180830381600087803b158015611ed457600080fd5b505af1158015611ee8573d6000803e3d6000fd5b50505050611ef46118b8565b6001600160a01b0316632f7206ce8c8c878c8b8d6040518763ffffffff1660e01b8152600401611f29969594939291906151f1565b600060405180830381600087803b158015611f4357600080fd5b505af1158015611f57573d6000803e3d6000fd5b50505050505050505b9550959350505050565b600082118015611f8257506001600160a01b03811615155b8015611f915750611f91612b01565b15610eba57611f9e6136d9565b6001600160a01b03166321cad77483836040518363ffffffff1660e01b8152600401611fcb92919061529d565b600060405180830381600087803b158015611fe557600080fd5b505af1158015611ff9573d6000803e3d6000fd5b505050505050565b6120096118b8565b6001600160a01b0316632d3169eb858585856040518563ffffffff1660e01b815260040161203a94939291906152b9565b600060405180830381600087803b15801561205457600080fd5b505af1158015612068573d6000803e3d6000fd5b5050505050505050565b600061207c612e12565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f7072696365446576696174696f6e5468726573686f6c64466163746f720000006040518363ffffffff1660e01b81526004016116229291906152ab565b600061098b6524b9b9bab2b960d11b612db5565b6000828201838110156104795760405162461bcd60e51b8152600401610629906153ef565b600061098b7044656c6567617465417070726f76616c7360781b612db5565b600080600061214a8860000151876000015189612e6c565b61215c575060009150819050806127a9565b612164613fb9565b61216c613f84565b6121746117b6565b60208101518b51604051633d00c50f60e11b81529293506001600160a01b0390911691637a018a1e916121a99160040161528f565b60206040518083038186803b1580156121c157600080fd5b505afa1580156121d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506121f99190810190614600565b60a083015260208101518851604051633d00c50f60e11b81526001600160a01b0390921691637a018a1e916122309160040161528f565b60206040518083038186803b15801561224857600080fd5b505afa15801561225c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122809190810190614600565b60c08301528951612294908a908d9061304e565b60e083018190526122b15750600093508392508291506127a99050565b60208101518a5160e08401518a5160a086015160c087015160405162d9ccd960e71b81526001600160a01b0390961695636ce66c80956122fb95909490939092909160040161531c565b60606040518083038186803b15801561231357600080fd5b505afa158015612327573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061234b919081019061473a565b6020850152835260408301528951885160a084015160c0850151612371939291906136f5565b60006123878b8a8560a001518660c00151613861565b6060850191909152905080156123aa5750600094508493508392506127a9915050565b6123bc83604001518460600151612cfb565b60408401519096506123d4908763ffffffff612d8d16565b94506123f18b600001518d8560e001518c600001518a8d8d6131b6565b93506001600160a01b03841615612406578397505b84156126615760208201518951604051631952982b60e21b81526001600160a01b039092169163654a60ac91612449918990631cd554d160e21b9060040161530e565b60206040518083038186803b15801561246157600080fd5b505afa158015612475573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124999190810190614600565b94506124a36120da565b6001600160a01b03166332608039631cd554d160e21b6040518263ffffffff1660e01b81526004016124d5919061528f565b60206040518083038186803b1580156124ed57600080fd5b505afa158015612501573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612525919081019061463d565b6001600160a01b031663867904b461253b61347e565b6001600160a01b031663eb1edd616040518163ffffffff1660e01b815260040160206040518083038186803b15801561257357600080fd5b505afa158015612587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125ab919081019061434c565b876040518363ffffffff1660e01b81526004016125c99291906151ae565b600060405180830381600087803b1580156125e357600080fd5b505af11580156125f7573d6000803e3d6000fd5b5050505061260361347e565b6001600160a01b03166322bf55ef866040518263ffffffff1660e01b815260040161262e919061528f565b600060405180830381600087803b15801561264857600080fd5b505af115801561265c573d6000803e3d6000fd5b505050505b6040805180820182528c5181528a51602080830191909152825180840190935285518352858101519083015261269691613493565b61269e6118b8565b6001600160a01b0316636c00f3108d8d600001518660e001518d600001518b8e6040518763ffffffff1660e01b81526004016126df969594939291906151f1565b600060405180830381600087803b1580156126f957600080fd5b505af115801561270d573d6000803e3d6000fd5b50505050600061271b6115c6565b11156127a55773aa5a3d7f04e15b22eb3664b56310aa18a3527ec7632f2de902838a8e600001518760e001518e600001518c8a606001516040518863ffffffff1660e01b815260040161277497969594939291906155e3565b60006040518083038186803b15801561278c57600080fd5b505af41580156127a0573d6000803e3d6000fd5b505050505b5050505b96509650969350505050565b600061098b6c45786368616e6765526174657360981b612db5565b600061098b6d21b4b931bab4ba213932b0b5b2b960911b612db5565b6060806127f76138b4565b60408051600b80825261018082019092529192506060919060208201610160803883390190505090506b53797374656d53746174757360a01b8160008151811061283d57fe5b6020026020010181815250506c45786368616e6765537461746560981b8160018151811061286757fe5b6020026020010181815250506c45786368616e6765526174657360981b8160028151811061289157fe5b602002602001018181525050680a6f2dce8d0cae8d2f60bb1b816003815181106128b757fe5b60200260200101818152505066119959541bdbdb60ca1b816004815181106128db57fe5b6020026020010181815250506d54726164696e675265776172647360901b8160058151811061290657fe5b6020026020010181815250507044656c6567617465417070726f76616c7360781b8160068151811061293457fe5b6020026020010181815250506524b9b9bab2b960d11b8160078151811061295757fe5b6020026020010181815250506844656274436163686560b81b8160088151811061297d57fe5b6020026020010181815250506d21b4b931bab4ba213932b0b5b2b960911b816009815181106129a857fe5b602002602001018181525050772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b81600a815181106110c357fe5b60608151835101604051908082528060200260200182016040528015612a0d578160200160208202803883390190505b50905060005b8351811015612a4f57838181518110612a2857fe5b6020026020010151828281518110612a3c57fe5b6020908102919091010152600101612a13565b5060005b8251811015612a9257828181518110612a6857fe5b6020026020010151828286510181518110612a7f57fe5b6020908102919091010152600101612a53565b5092915050565b6000612aa3612e12565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f61746f6d69634d6178566f6c756d65506572426c6f636b0000000000000000006040518363ffffffff1660e01b81526004016116229291906152ab565b6000612b0b612e12565b6001600160a01b031663d994502d6d53797374656d53657474696e677360901b741d1c98591a5b99d4995dd85c991cd15b98589b1959605a1b6040518363ffffffff1660e01b8152600401612b619291906152ab565b60206040518083038186803b158015612b7957600080fd5b505afa158015612b8d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098b91908101906145c4565b600080600080612bc085613905565b91509150600080612bd088613905565b9092509050612be5848363ffffffff6120ee16565b610120890151909650861180612bfb5786612c02565b8861012001515b9650868180612c0e5750845b80612c165750825b9650965050505050509250929050565b6000806000806000806000612c396127b5565b6001600160a01b03166326bd30fa8b8d8c8c6040518563ffffffff1660e01b8152600401612c6a949392919061552e565b60806040518083038186803b158015612c8257600080fd5b505afa158015612c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cba91908101906147ea565b919650945092509050612ccd8a8a61174b565b9450612cd98186612cfb565b9650612ceb818863ffffffff612d8d16565b9550509499939850945094509450565b6000610479612d80837384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4857600080fd5b505af4158015612d5c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b19190810190614600565b849063ffffffff6139d616565b600082821115612daf5760405162461bcd60e51b81526004016106299061542f565b50900390565b60008181526003602090815260408083205490516001600160a01b039091169182151591612de59186910161514c565b60405160208183030381529060405290612a925760405162461bcd60e51b8152600401610629919061539e565b600061098b6e466c657869626c6553746f7261676560881b612db5565b600061098b772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b612db5565b600061098b6844656274436163686560b81b612db5565b600082841415612e8e5760405162461bcd60e51b8152600401610629906153bf565b60008211612eae5760405162461bcd60e51b81526004016106299061541f565b600080631cd554d160e21b861415612ec95760008080612f4e565b612ed16127b5565b6001600160a01b031663045056f8876040518263ffffffff1660e01b8152600401612efc919061528f565b606060405180830381600087803b158015612f1657600080fd5b505af1158015612f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f4e91908101906146aa565b9250925050600080631cd554d160e21b871415612f6e5760008080612ff3565b612f766127b5565b6001600160a01b031663045056f8886040518263ffffffff1660e01b8152600401612fa1919061528f565b606060405180830381600087803b158015612fbb57600080fd5b505af1158015612fcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612ff391908101906146aa565b925092505082156130165760405162461bcd60e51b8152600401610629906154df565b80156130345760405162461bcd60e51b81526004016106299061544f565b83158015613040575081155b9450505050505b9392505050565b600080600073aa5a3d7f04e15b22eb3664b56310aa18a3527ec76377cd29a56130756117b6565b878760006130816115c6565b6040518663ffffffff1660e01b81526004016130a1959493929190615567565b60606040518083038186803b1580156130b957600080fd5b505af41580156130cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130f1919081019061473a565b889550909350915050801561310f5761310c85858885610990565b92505b50509392505050565b60045460009067ffffffffffffffff1642146131345781613151565b60045461315190600160401b90046001600160c01b0316836120ee565b90508260a001518111156131775760405162461bcd60e51b81526004016106299061550f565b600480546001600160c01b03909216600160401b0267ffffffffffffffff42811667ffffffffffffffff19909416939093179092169190911790555050565b60006131c06120da565b6001600160a01b03166332608039896040518263ffffffff1660e01b81526004016131eb919061528f565b60206040518083038186803b15801561320357600080fd5b505afa158015613217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061323b919081019061463d565b6001600160a01b0316639dc29fac88886040518363ffffffff1660e01b81526004016132689291906151ae565b600060405180830381600087803b15801561328257600080fd5b505af1158015613296573d6000803e3d6000fd5b5050505060006132a46120da565b6001600160a01b03166332608039876040518263ffffffff1660e01b81526004016132cf919061528f565b60206040518083038186803b1580156132e757600080fd5b505afa1580156132fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061331f919081019061463d565b905082156134115760008190506133a8816001600160a01b031663ec5568896040518163ffffffff1660e01b815260040160206040518083038186803b15801561336857600080fd5b505afa15801561337c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506133a0919081019061463d565b86888a613a00565b60405163219e412d60e21b81529093506001600160a01b0383169063867904b4906133d99086908a906004016151ae565b600060405180830381600087803b1580156133f357600080fd5b505af1158015613407573d6000803e3d6000fd5b5050505050613472565b60405163219e412d60e21b81526001600160a01b0382169063867904b49061343f90879089906004016151ae565b600060405180830381600087803b15801561345957600080fd5b505af115801561346d573d6000803e3d6000fd5b505050505b50979650505050505050565b600061098b66119959541bdbdb60ca1b612db5565b8151600090631cd554d160e21b14806134b657506020830151631cd554d160e21b145b90506000816134c65760036134c9565b60025b60ff1690506060816040519080825280602002602001820160405280156134fa578160200160208202803883390190505b50905084600060200201518160008151811061351257fe5b602090810291909101015284600160200201518160018151811061353257fe5b60200260200101818152505060608260405190808252806020026020018201604052801561356a578160200160208202803883390190505b50905084600060200201518160008151811061358257fe5b60209081029190910101528460016020020151816001815181106135a257fe5b6020026020010181815250508361366a57631cd554d160e21b826002815181106135c857fe5b6020026020010181815250507384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561361857600080fd5b505af415801561362c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506136509190810190614600565b8160028151811061365d57fe5b6020026020010181815250505b613672612e55565b6001600160a01b03166317b38db483836040518363ffffffff1660e01b815260040161369f92919061525c565b600060405180830381600087803b1580156136b957600080fd5b505af11580156136cd573d6000803e3d6000fd5b50505050505050505050565b600061098b6d54726164696e675265776172647360901b612db5565b828414156137155760405162461bcd60e51b8152600401610629906153bf565b6040805160028082526060808301845292602083019080388339019050509050848160008151811061374357fe5b602002602001018181525050838160018151811061375d57fe5b60209081029190910101526040805160028082526060828101909352816020016020820280388339019050509050838160008151811061379957fe5b60200260200101818152505082816001815181106137b357fe5b6020026020010181815250506137c76127b5565b6001600160a01b031663d89ee86183836040518363ffffffff1660e01b81526004016137f492919061525c565b60206040518083038186803b15801561380c57600080fd5b505afa158015613820573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061384491908101906145c4565b15611ff95760405162461bcd60e51b8152600401610629906154ef565b60008060006138838661010001518861010001516120ee90919063ffffffff16565b9050600061389388888888613b43565b935090506138a7828263ffffffff6120ee16565b9350505094509492505050565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b816000815181106138f657fe5b60200260200101818152505090565b600080631cd554d160e21b836000015114806139275750600183610140015111155b15613937575060009050806139d1565b60006139416127b5565b8451604051633d00c50f60e11b81526001600160a01b039290921691637a018a1e9161396f9160040161528f565b60206040518083038186803b15801561398757600080fd5b505afa15801561399b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506139bf9190810190614600565b90506139cb8482613bbc565b92509250505b915091565b6000670de0b6b3a76400006139f1848463ffffffff613cc616565b816139f857fe5b049392505050565b6000606960f81b6001600160f81b031983831a60f81b161415613a355760405162461bcd60e51b8152600401610629906154cf565b6000613a7d613a42613d00565b6040518060400160405280601b81526020017f436f756c64206e6f7420637265617465206e6577207653796e74680000000000815250613d24565b600254604051638d7017d360e01b81529192506001600160a01b0380841692638d7017d392613ab9928b929116908a908a908a90600401615376565b600060405180830381600087803b158015613ad357600080fd5b505af1158015613ae7573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b03167fb5ec76d79549c775883022e4426db5cd36bd5307f216cdb341554c301548ef9f838688604051613b32939291906151c9565b60405180910390a395945050505050565b600080600080613b538786613bbc565b91509150600080613b648a89613bbc565b9092509050613b79848363ffffffff6120ee16565b6101208b0151909650861180613b8f5786613b96565b8a61012001515b9650868180613ba25750845b80613baa5750825b96509650505050505094509492505050565b600080631cd554d160e21b84600001511480613bde5750600184610140015111155b15613bee57506000905080611161565b6060613bf86127b5565b8551610140870151604051630ed7624560e41b81526001600160a01b03939093169263ed76245092613c30929091899060040161530e565b60006040518083038186803b158015613c4857600080fd5b505afa158015613c5c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613c849190810190614565565b5080915050613c9e81866101600151876101800151613d6e565b610120860151909350831180613cb45783613cbb565b8561012001515b969095509350505050565b600082613cd55750600061047c565b82820282848281613ce257fe5b04146104795760405162461bcd60e51b8152600401610629906154af565b600061098b755669727475616c53796e74684d6173746572636f707960501b612db5565b60006060613d3184613df8565b90506037602082016000f09150826001600160a01b038316613d665760405162461bcd60e51b8152600401610629919061539e565b505092915050565b6000835160001415613d8257506000613047565b8351600090600019015b8015610ab857613da2828563ffffffff6139d616565b91506000613dda876001840381518110613db857fe5b6020026020010151888481518110613dcc57fe5b602002602001015188613e54565b9050613dec838263ffffffff6120ee16565b92505060001901613d8c565b604051606090613e3e90693d602d80600a3d3981f360b01b9069363d3d373d3d3d363d7360b01b9085906e5af43d82803e903d91602b57fd5bf360881b90602001615104565b6040516020818303038152906040529050919050565b600082613e6357506000613047565b6000838511613e7457848403613e78565b8385035b90506000613e8c828663ffffffff613ea816565b9050838111613e9c57600061310c565b92909203949350505050565b600061047982613ec685670de0b6b3a764000063ffffffff613cc616565b9063ffffffff613ed216565b6000808211613ef35760405162461bcd60e51b81526004016106299061543f565b6000828481613efe57fe5b04949350505050565b604051806101a001604052806000801916815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b803561047c816157bd565b805161047c816157bd565b600082601f83011261402557600080fd5b8151614038614033826156c8565b6156a1565b915081818352602084019350602081019050838561010084028201111561405e57600080fd5b60005b8381101561408d5781614074888261413e565b8452506020909201916101009190910190600101614061565b5050505092915050565b600082601f8301126140a857600080fd5b81516140b6614033826156c8565b915081818352602084019350602081019050838560208402820111156140db57600080fd5b60005b8381101561408d57816140f18882614128565b84525060209283019291909101906001016140de565b803561047c816157d4565b805161047c816157d4565b803561047c816157dd565b805161047c816157dd565b805161047c816157e6565b6000610100828403121561415157600080fd5b61415c6101006156a1565b9050600061416a8484614128565b825250602061417b84848301614128565b602083015250604061418f84828501614128565b60408301525060606141a384828501614128565b60608301525060806141b784828501614128565b60808301525060a06141cb84828501614128565b60a08301525060c06141df84828501614128565b60c08301525060e06141f384828501614128565b60e08301525092915050565b60006101a0828403121561421257600080fd5b61421d6101a06156a1565b9050600061422b8484614128565b825250602061423c84848301614009565b602083015250604061425084828501614009565b604083015250606061426484828501614128565b606083015250608061427884828501614128565b60808301525060a061428c84828501614128565b60a08301525060c06142a084828501614128565b60c08301525060e06142b484828501614128565b60e0830152506101006142c984828501614128565b610100830152506101206142df84828501614128565b610120830152506101406142f584828501614128565b6101408301525061016061430b84828501614128565b6101608301525061018061432184828501614128565b6101808301525092915050565b60006020828403121561434057600080fd5b6000610d3c8484613ffe565b60006020828403121561435e57600080fd5b6000610d3c8484614009565b60008060008060008060008060006101208a8c03121561438957600080fd5b60006143958c8c613ffe565b99505060206143a68c828d01613ffe565b98505060406143b78c828d0161411d565b97505060606143c88c828d0161411d565b96505060806143d98c828d0161411d565b95505060a06143ea8c828d01613ffe565b94505060c06143fb8c828d01614107565b93505060e061440c8c828d01613ffe565b92505061010061441e8c828d0161411d565b9150509295985092959850929598565b6000806040838503121561444157600080fd5b600061444d8585613ffe565b925050602061445e8582860161411d565b9150509250929050565b600080600080600080600060e0888a03121561448357600080fd5b600061448f8a8a613ffe565b97505060206144a08a828b0161411d565b96505060406144b18a828b0161411d565b95505060606144c28a828b0161411d565b94505060806144d38a828b01613ffe565b93505060a06144e48a828b0161411d565b92505060c06144f58a828b0161411d565b91505092959891949750929550565b6000806000806080858703121561451a57600080fd5b60006145268787613ffe565b94505060206145378782880161411d565b93505060406145488782880161411d565b92505060606145598782880161411d565b91505092959194509250565b6000806040838503121561457857600080fd5b825167ffffffffffffffff81111561458f57600080fd5b61459b85828601614097565b925050602083015167ffffffffffffffff8111156145b857600080fd5b61445e85828601614097565b6000602082840312156145d657600080fd5b6000610d3c8484614112565b6000602082840312156145f457600080fd5b6000610d3c848461411d565b60006020828403121561461257600080fd5b6000610d3c8484614128565b6000806040838503121561463157600080fd5b600061444d858561411d565b60006020828403121561464f57600080fd5b6000610d3c8484614133565b60006101a0828403121561466e57600080fd5b6000610d3c84846141ff565b6000806040838503121561468d57600080fd5b60006146998585614128565b925050602061445e85828601614112565b6000806000606084860312156146bf57600080fd5b60006146cb8686614128565b93505060206146dc86828701614112565b92505060406146ed86828701614112565b9150509250925092565b60008060006060848603121561470c57600080fd5b6000614718868661411d565b93505060206147298682870161411d565b92505060406146ed8682870161411d565b60008060006060848603121561474f57600080fd5b600061475b8686614128565b935050602061476c86828701614128565b92505060406146ed86828701614128565b6000806000806080858703121561479357600080fd5b600061479f8787614128565b94505060206147b087828801614128565b93505060406147c187828801614128565b925050606085015167ffffffffffffffff8111156147de57600080fd5b61455987828801614014565b6000806000806080858703121561480057600080fd5b600061480c8787614128565b945050602061481d87828801614128565b935050604061482e87828801614128565b925050606061455987828801614128565b600061484b8383614949565b505060200190565b61485c81615765565b82525050565b61485c81615701565b61485c61487782615701565b61579c565b6000614887826156ef565b61489181856156f3565b935061489c836156e9565b8060005b838110156148ca5781516148b4888261483f565b97506148bf836156e9565b9250506001016148a0565b509495945050505050565b60006148e0826156ef565b6148ea81856156f3565b93506148f5836156e9565b8060005b838110156148ca57815161490d888261483f565b9750614918836156e9565b9250506001016148f9565b61485c8161570c565b61485c61493882615711565b610864565b61485c6149388261571e565b61485c81610864565b61485c61493882610864565b61485c81615735565b6000614972826156ef565b61497c81856156f3565b935061498c818560208601615770565b614995816157ad565b9093019392505050565b60006149ac6016836156f3565b751cdc98c81cde5b9d1a081c985d19481a5b9d985b1a5960521b815260200192915050565b60006149de6013836156f3565b72086c2dc4ee840c4ca40e6c2daca40e6f2dce8d606b1b815260200192915050565b6000614a0d6035836156f3565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b6000614a64601d836156f3565b7f4e6f7420617070726f76656420746f20616374206f6e20626568616c66000000815260200192915050565b6000614a9d601b836156f3565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000614ad66017836156f3565b7f646573742073796e7468207261746520696e76616c6964000000000000000000815260200192915050565b6000614b0f601d836156f3565b7f41746f6d6963207261746520646576696174657320746f6f206d756368000000815260200192915050565b6000614b48600b836156f3565b6a16995c9bc8185b5bdd5b9d60aa1b815260200192915050565b6000614b6f601e836156f3565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000614ba8601a836156f3565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b6000614be16011836156fc565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b6000614c0e601a836156f3565b7f646573742072617465207374616c65206f7220666c6167676564000000000000815260200192915050565b6000614c47603a836156f3565b7f54686520616d6f756e742072656365697665642069732062656c6f772074686581527f206d696e696d756d20616d6f756e74207370656369666965642e000000000000602082015260400192915050565b6000614ca66045836156f3565b7f45786368616e6765723a204f6e6c792073796e746865746978206f722061207381527f796e746820636f6e74726163742063616e20706572666f726d2074686973206160208201526431ba34b7b760d91b604082015260600192915050565b6000614d136017836156f3565b7f446573742073796e746820746f6f20766f6c6174696c65000000000000000000815260200192915050565b6000614d4c602f836156f3565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b6000614d9d600c836156f3565b6b746f6f20766f6c6174696c6560a01b815260200192915050565b6000614dc56021836156f3565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614e08601b836156f3565b7f65786368616e676520726174657320746f6f20766f6c6174696c650000000000815260200192915050565b6000614e41601c836156f3565b7f43616e6e6f74207669727475616c697a6520746869732073796e746800000000815260200192915050565b6000614e7a6019836156fc565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000614eb36019836156f3565b7f7372632072617465207374616c65206f7220666c616767656400000000000000815260200192915050565b6000614eec601e836156f3565b7f7372632f646573742072617465207374616c65206f7220666c61676765640000815260200192915050565b6000614f256016836156f3565b755372632073796e746820746f6f20766f6c6174696c6560501b815260200192915050565b6000614f576016836156f3565b7514dd5c9c185cdcd959081d9bdb1d5b59481b1a5b5a5d60521b815260200192915050565b80516101a0830190614f8e8482614949565b506020820151614fa16020850182614862565b506040820151614fb46040850182614862565b506060820151614fc76060850182614949565b506080820151614fda6080850182614949565b5060a0820151614fed60a0850182614949565b5060c082015161500060c0850182614949565b5060e082015161501360e0850182614949565b50610100820151615028610100850182614949565b5061012082015161503d610120850182614949565b50610140820151615052610140850182614949565b50610160820151615067610160850182614949565b5061018082015161507c610180850182614949565b50505050565b805160c0830190615093848261495e565b5060208201516150a6602085018261495e565b5060408201516150b9604085018261495e565b5060608201516150cc606085018261495e565b5060808201516150df608085018261495e565b5060a082015161507c60a085018261495e565b61485c8161574c565b61485c81615758565b6000615110828761492c565b600a82019150615120828661492c565b600a82019150615130828561486b565b601482019150615140828461493d565b50600f01949350505050565b600061515782614bd4565b91506151638284614952565b50602001919050565b600061515782614e6d565b6020810161047c8284614862565b6020810161047c8284614853565b604081016151a18285614862565b6130476020830184614862565b604081016151bc8285614862565b6130476020830184614949565b606081016151d78286614862565b6151e46020830185614949565b610d3c6040830184614949565b60c081016151ff8289614862565b61520c6020830188614949565b6152196040830187614949565b6152266060830186614949565b6152336080830185614949565b61524060a0830184614862565b979650505050505050565b60208082528101610479818461487c565b6040808252810161526d818561487c565b90508181036020830152610d3c81846148d5565b6020810161047c8284614923565b6020810161047c8284614949565b604081016151a18285614949565b604081016151bc8285614949565b608081016152c78287614949565b6152d46020830186614949565b6152e16040830185614949565b6104b66060830184614949565b604081016152fc8285614949565b8181036020830152610d3c8184614967565b606081016151d78286614949565b60a0810161532a8288614949565b6153376020830187614949565b6153446040830186614949565b6153516060830185614949565b61535e6080830184614949565b9695505050505050565b6020810161047c828461495e565b60a08101615384828861495e565b615391602083018761495e565b6153446040830186614862565b602080825281016104798184614967565b6020808252810161047c8161499f565b6020808252810161047c816149d1565b6020808252810161047c81614a00565b6020808252810161047c81614a57565b6020808252810161047c81614a90565b6020808252810161047c81614ac9565b6020808252810161047c81614b02565b6020808252810161047c81614b3b565b6020808252810161047c81614b62565b6020808252810161047c81614b9b565b6020808252810161047c81614c01565b6020808252810161047c81614c3a565b6020808252810161047c81614c99565b6020808252810161047c81614d06565b6020808252810161047c81614d3f565b6020808252810161047c81614d90565b6020808252810161047c81614db8565b6020808252810161047c81614dfb565b6020808252810161047c81614e34565b6020808252810161047c81614ea6565b6020808252810161047c81614edf565b6020808252810161047c81614f18565b6020808252810161047c81614f4a565b6101a0810161047c8284614f7c565b610500810161553d8287614f7c565b61554b6101a0830186614949565b6155596101c0830185614f7c565b6104b6610360830184614f7c565b61014081016155768288615082565b61558360c0830187614862565b61559060e0830186614949565b61559e610100830185614923565b61535e610120830184614949565b61012081016155bb8287615082565b6155c860c0830186614862565b6155d560e0830185614949565b6104b6610100830184614949565b61018081016155f2828a615082565b6155ff60c0830189614862565b61560c60e0830188614949565b61561a610100830187614949565b615628610120830186614949565b615636610140830185614949565b615644610160830184614949565b98975050505050505050565b6040810161565e8285614949565b6130476020830184614923565b604081016156798285614949565b613047602083018461495e565b6040810161569482856150fb565b61304760208301846150f2565b60405181810167ffffffffffffffff811182821017156156c057600080fd5b604052919050565b600067ffffffffffffffff8211156156df57600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b919050565b600061047c82615740565b151590565b6001600160b01b03191690565b70ffffffffffffffffffffffffffffffffff191690565b600061047c82615701565b6001600160a01b031690565b6001600160c01b031690565b67ffffffffffffffff1690565b600061047c82615735565b60005b8381101561578b578181015183820152602001615773565b8381111561507c5750506000910152565b600061047c82600061047c826157b7565b601f01601f191690565b60601b90565b6157c681615701565b81146157d157600080fd5b50565b6157c68161570c565b6157c681610864565b6157c68161573556fea365627a7a72315820577fb23de8a6037dcd49350690073c896549aae5811f541f95c21022701d053b6c6578706572696d656e74616cf564736f6c63430005100040
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000302d2451d9f47620374b54c521423bf0403916a20000000000000000000000004e3b31eb0e5cb73641ee1e65e7dcefe520ba3ef2
-----Decoded View---------------
Arg [0] : _owner (address): 0x302d2451d9f47620374B54c521423Bf0403916A2
Arg [1] : _resolver (address): 0x4E3b31eB0E5CB73641EE1E65E7dCEFe520bA3ef2
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000302d2451d9f47620374b54c521423bf0403916a2
Arg [1] : 0000000000000000000000004e3b31eb0e5cb73641ee1e65e7dcefe520ba3ef2
Libraries Used
SafeDecimalMath : 0x84d626b2bb4d0f064067e4bf80fce7055d8f3e7bSystemSettingsLib : 0x4a39aef2281ac0d192a9c4783604833ba8f31174SignedSafeDecimalMath : 0x728a2b79cad691531cc1146ef802617ff50c7095ExchangeSettlementLib : 0xaa5a3d7f04e15b22eb3664b56310aa18a3527ec7
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.