Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Nominate New Own... | 15890558 | 804 days ago | IN | 0 ETH | 0.00213352 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ExchangeRatesWithDexPricing
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: ExchangeRatesWithDexPricing.sol * * Latest source (may be newer): https://github.com/Synthetixio/synthetix/blob/master/contracts/ExchangeRatesWithDexPricing.sol * Docs: https://docs.synthetix.io/contracts/ExchangeRatesWithDexPricing * * Contract Dependencies: * - ExchangeRates * - IAddressResolver * - IExchangeRates * - MixinResolver * - MixinSystemSettings * - Owned * Libraries: * - 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); } } // 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); } pragma experimental ABIEncoderV2; // 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 ); } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // Libraries // https://docs.synthetix.io/contracts/source/libraries/safedecimalmath library SafeDecimalMath { using SafeMath for uint; /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint public constant UNIT = 10**uint(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(uint x, uint y) internal pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return x.mul(y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(uint x, uint y) internal pure returns (uint) { /* Reintroduce the UNIT factor that will be divided out by y. */ return x.mul(UNIT).div(y); } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function _divideDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint resultTimesTen = x.mul(precisionUnit * 10).div(y); if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(uint i) internal pure returns (uint) { uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } // Computes `a - b`, setting the value to 0 if b > a. function floorsub(uint a, uint b) internal pure returns (uint) { return b >= a ? 0 : a - b; } /* ---------- Utilities ---------- */ /* * Absolute value of the input, returned as a signed number. */ function signedAbs(int x) internal pure returns (int) { return x < 0 ? -x : x; } /* * Absolute value of the input, returned as an unsigned number. */ function abs(int x) internal pure returns (uint) { return uint(signedAbs(x)); } } interface AggregatorInterface { function latestAnswer() external view returns (int256); function latestTimestamp() external view returns (uint256); function latestRound() external view returns (uint256); function getAnswer(uint256 roundId) external view returns (int256); function getTimestamp(uint256 roundId) external view returns (uint256); event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp); event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); } interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } /** * @title The V2 & V3 Aggregator Interface * @notice Solidity V0.5 does not allow interfaces to inherit from other * interfaces so this contract is a combination of v0.5 AggregatorInterface.sol * and v0.5 AggregatorV3Interface.sol. */ interface AggregatorV2V3Interface { // // V2 Interface: // function latestAnswer() external view returns (int256); function latestTimestamp() external view returns (uint256); function latestRound() external view returns (uint256); function getAnswer(uint256 roundId) external view returns (int256); function getTimestamp(uint256 roundId) external view returns (uint256); event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp); event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); // // V3 Interface: // function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } interface FlagsInterface { function getFlag(address) external view returns (bool); function getFlags(address[] calldata) external view returns (bool[] memory); function raiseFlag(address) external; function raiseFlags(address[] calldata) external; function lowerFlags(address[] calldata) external; function setRaisingAccessController(address) external; } // 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); } // Inheritance // Libraries // Internal references // AggregatorInterface from Chainlink represents a decentralized pricing network for a single currency key // FlagsInterface from Chainlink addresses SIP-76 // https://docs.synthetix.io/contracts/source/contracts/exchangerates contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { using SafeMath for uint; using SafeDecimalMath for uint; bytes32 public constant CONTRACT_NAME = "ExchangeRates"; bytes32 internal constant CONTRACT_CIRCUIT_BREAKER = "CircuitBreaker"; //slither-disable-next-line naming-convention bytes32 internal constant sUSD = "sUSD"; // Decentralized oracle networks that feed into pricing aggregators mapping(bytes32 => AggregatorV2V3Interface) public aggregators; mapping(bytes32 => uint8) public currencyKeyDecimals; // List of aggregator keys for convenient iteration bytes32[] public aggregatorKeys; // ========== CONSTRUCTOR ========== constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) {} /* ========== MUTATIVE FUNCTIONS ========== */ function addAggregator(bytes32 currencyKey, address aggregatorAddress) external onlyOwner { AggregatorV2V3Interface aggregator = AggregatorV2V3Interface(aggregatorAddress); // This check tries to make sure that a valid aggregator is being added. // It checks if the aggregator is an existing smart contract that has implemented `latestTimestamp` function. require(aggregator.latestRound() >= 0, "Given Aggregator is invalid"); uint8 decimals = aggregator.decimals(); // This contract converts all external rates to 18 decimal rates, so adding external rates with // higher precision will result in losing precision internally. 27 decimals will result in losing 9 decimal // places, which should leave plenty precision for most things. require(decimals <= 27, "Aggregator decimals should be lower or equal to 27"); if (address(aggregators[currencyKey]) == address(0)) { aggregatorKeys.push(currencyKey); } aggregators[currencyKey] = aggregator; currencyKeyDecimals[currencyKey] = decimals; emit AggregatorAdded(currencyKey, address(aggregator)); } function removeAggregator(bytes32 currencyKey) external onlyOwner { address aggregator = address(aggregators[currencyKey]); require(aggregator != address(0), "No aggregator exists for key"); delete aggregators[currencyKey]; delete currencyKeyDecimals[currencyKey]; bool wasRemoved = removeFromArray(currencyKey, aggregatorKeys); if (wasRemoved) { emit AggregatorRemoved(currencyKey, aggregator); } } function rateWithSafetyChecks(bytes32 currencyKey) external returns ( uint rate, bool broken, bool staleOrInvalid ) { address aggregatorAddress = address(aggregators[currencyKey]); require(currencyKey == sUSD || aggregatorAddress != address(0), "No aggregator for asset"); RateAndUpdatedTime memory rateAndTime = _getRateAndUpdatedTime(currencyKey); if (currencyKey == sUSD) { return (rateAndTime.rate, false, false); } rate = rateAndTime.rate; broken = circuitBreaker().probeCircuitBreaker(aggregatorAddress, rateAndTime.rate); staleOrInvalid = _rateIsStaleWithTime(getRateStalePeriod(), rateAndTime.time) || _rateIsFlagged(currencyKey, FlagsInterface(getAggregatorWarningFlags())); } /* ========== VIEWS ========== */ function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](1); newAddresses[0] = CONTRACT_CIRCUIT_BREAKER; return combineArrays(existingAddresses, newAddresses); } function circuitBreaker() internal view returns (ICircuitBreaker) { return ICircuitBreaker(requireAndGetAddress(CONTRACT_CIRCUIT_BREAKER)); } function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory currencies) { uint count = 0; currencies = new bytes32[](aggregatorKeys.length); for (uint i = 0; i < aggregatorKeys.length; i++) { bytes32 currencyKey = aggregatorKeys[i]; if (address(aggregators[currencyKey]) == aggregator) { currencies[count++] = currencyKey; } } } function rateStalePeriod() external view returns (uint) { return getRateStalePeriod(); } function aggregatorWarningFlags() external view returns (address) { return getAggregatorWarningFlags(); } function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time) { RateAndUpdatedTime memory rateAndTime = _getRateAndUpdatedTime(currencyKey); return (rateAndTime.rate, rateAndTime.time); } function getLastRoundIdBeforeElapsedSecs( bytes32 currencyKey, uint startingRoundId, uint startingTimestamp, uint timediff ) external view returns (uint) { uint roundId = startingRoundId; uint nextTimestamp = 0; while (true) { (, nextTimestamp) = _getRateAndTimestampAtRound(currencyKey, roundId + 1); // if there's no new round, then the previous roundId was the latest if (nextTimestamp == 0 || nextTimestamp > startingTimestamp + timediff) { return roundId; } roundId++; } return roundId; } function getCurrentRoundId(bytes32 currencyKey) external view returns (uint) { return _getCurrentRoundId(currencyKey); } function effectiveValueAndRatesAtRound( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, uint roundIdForSrc, uint roundIdForDest ) external view returns ( uint value, uint sourceRate, uint destinationRate ) { (sourceRate, ) = _getRateAndTimestampAtRound(sourceCurrencyKey, roundIdForSrc); // If there's no change in the currency, then just return the amount they gave us if (sourceCurrencyKey == destinationCurrencyKey) { destinationRate = sourceRate; value = sourceAmount; } else { (destinationRate, ) = _getRateAndTimestampAtRound(destinationCurrencyKey, roundIdForDest); // prevent divide-by 0 error (this happens if the dest is not a valid rate) if (destinationRate > 0) { // Calculate the effective value by going from source -> USD -> destination value = sourceAmount.multiplyDecimalRound(sourceRate).divideDecimalRound(destinationRate); } } } function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time) { return _getRateAndTimestampAtRound(currencyKey, roundId); } function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256) { return _getUpdatedTime(currencyKey); } function lastRateUpdateTimesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory) { uint[] memory lastUpdateTimes = new uint[](currencyKeys.length); for (uint i = 0; i < currencyKeys.length; i++) { lastUpdateTimes[i] = _getUpdatedTime(currencyKeys[i]); } return lastUpdateTimes; } function effectiveValue( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint value) { (value, , ) = _effectiveValueAndRates(sourceCurrencyKey, sourceAmount, destinationCurrencyKey); } function effectiveValueAndRates( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns ( uint value, uint sourceRate, uint destinationRate ) { return _effectiveValueAndRates(sourceCurrencyKey, sourceAmount, destinationCurrencyKey); } // SIP-120 Atomic exchanges function effectiveAtomicValueAndRates( bytes32, uint, bytes32 ) public view returns ( uint value, uint systemValue, uint systemSourceRate, uint systemDestinationRate ) { _notImplemented(); } function effectiveAtomicValueAndRates( IDirectIntegrationManager.ParameterIntegrationSettings memory, uint, IDirectIntegrationManager.ParameterIntegrationSettings memory, IDirectIntegrationManager.ParameterIntegrationSettings memory ) public view returns ( uint value, uint systemValue, uint systemSourceRate, uint systemDestinationRate ) { _notImplemented(); } function rateForCurrency(bytes32 currencyKey) external view returns (uint) { return _getRateAndUpdatedTime(currencyKey).rate; } /// @notice getting N rounds of rates for a currency at a specific round /// @param currencyKey the currency key /// @param numRounds the number of rounds to get /// @param roundId the round id /// @return a list of rates and a list of times function ratesAndUpdatedTimeForCurrencyLastNRounds( bytes32 currencyKey, uint numRounds, uint roundId ) external view returns (uint[] memory rates, uint[] memory times) { rates = new uint[](numRounds); times = new uint[](numRounds); roundId = roundId > 0 ? roundId : _getCurrentRoundId(currencyKey); for (uint i = 0; i < numRounds; i++) { // fetch the rate and treat is as current, so inverse limits if frozen will always be applied // regardless of current rate (rates[i], times[i]) = _getRateAndTimestampAtRound(currencyKey, roundId); if (roundId == 0) { // if we hit the last round, then return what we have return (rates, times); } else { roundId--; } } } function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory) { uint[] memory _localRates = new uint[](currencyKeys.length); for (uint i = 0; i < currencyKeys.length; i++) { _localRates[i] = _getRate(currencyKeys[i]); } return _localRates; } function rateAndInvalid(bytes32 currencyKey) public view returns (uint rate, bool isInvalid) { RateAndUpdatedTime memory rateAndTime = _getRateAndUpdatedTime(currencyKey); if (currencyKey == sUSD) { return (rateAndTime.rate, false); } return ( rateAndTime.rate, _rateIsStaleWithTime(getRateStalePeriod(), rateAndTime.time) || _rateIsFlagged(currencyKey, FlagsInterface(getAggregatorWarningFlags())) || _rateIsCircuitBroken(currencyKey, rateAndTime.rate) ); } function ratesAndInvalidForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory rates, bool anyRateInvalid) { rates = new uint[](currencyKeys.length); uint256 _rateStalePeriod = getRateStalePeriod(); // fetch all flags at once bool[] memory flagList = getFlagsForRates(currencyKeys); for (uint i = 0; i < currencyKeys.length; i++) { // do one lookup of the rate & time to minimize gas RateAndUpdatedTime memory rateEntry = _getRateAndUpdatedTime(currencyKeys[i]); rates[i] = rateEntry.rate; if (!anyRateInvalid && currencyKeys[i] != sUSD) { anyRateInvalid = flagList[i] || _rateIsStaleWithTime(_rateStalePeriod, rateEntry.time) || _rateIsCircuitBroken(currencyKeys[i], rateEntry.rate); } } } function rateIsStale(bytes32 currencyKey) external view returns (bool) { return _rateIsStale(currencyKey, getRateStalePeriod()); } function rateIsInvalid(bytes32 currencyKey) external view returns (bool) { (, bool invalid) = rateAndInvalid(currencyKey); return invalid; } function rateIsFlagged(bytes32 currencyKey) external view returns (bool) { return _rateIsFlagged(currencyKey, FlagsInterface(getAggregatorWarningFlags())); } function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool) { // Loop through each key and check whether the data point is stale. uint256 _rateStalePeriod = getRateStalePeriod(); bool[] memory flagList = getFlagsForRates(currencyKeys); for (uint i = 0; i < currencyKeys.length; i++) { if (currencyKeys[i] == sUSD) { continue; } RateAndUpdatedTime memory rateEntry = _getRateAndUpdatedTime(currencyKeys[i]); if ( flagList[i] || _rateIsStaleWithTime(_rateStalePeriod, rateEntry.time) || _rateIsCircuitBroken(currencyKeys[i], rateEntry.rate) ) { return true; } } return false; } /// this method checks whether any rate is: /// 1. flagged /// 2. stale with respect to current time (now) function anyRateIsInvalidAtRound(bytes32[] calldata currencyKeys, uint[] calldata roundIds) external view returns (bool) { // Loop through each key and check whether the data point is stale. require(roundIds.length == currencyKeys.length, "roundIds must be the same length as currencyKeys"); uint256 _rateStalePeriod = getRateStalePeriod(); bool[] memory flagList = getFlagsForRates(currencyKeys); for (uint i = 0; i < currencyKeys.length; i++) { if (currencyKeys[i] == sUSD) { continue; } // NOTE: technically below `_rateIsStaleWithTime` is supposed to be called with the roundId timestamp in consideration, and `_rateIsCircuitBroken` is supposed to be // called with the current rate (or just not called at all) // but thats not how the functionality has worked prior to this change so that is why it works this way here // if you are adding new code taht calls this function and the rate is a long time ago, note that this function may resolve an invalid rate when its actually valid! (uint rate, uint time) = _getRateAndTimestampAtRound(currencyKeys[i], roundIds[i]); if (flagList[i] || _rateIsStaleWithTime(_rateStalePeriod, time) || _rateIsCircuitBroken(currencyKeys[i], rate)) { return true; } } return false; } function synthTooVolatileForAtomicExchange(bytes32) public view returns (bool) { _notImplemented(); } function synthTooVolatileForAtomicExchange(IDirectIntegrationManager.ParameterIntegrationSettings memory) public view returns (bool) { _notImplemented(); } /* ========== INTERNAL FUNCTIONS ========== */ function getFlagsForRates(bytes32[] memory currencyKeys) internal view returns (bool[] memory flagList) { FlagsInterface _flags = FlagsInterface(getAggregatorWarningFlags()); // fetch all flags at once if (_flags != FlagsInterface(0)) { address[] memory _aggregators = new address[](currencyKeys.length); for (uint i = 0; i < currencyKeys.length; i++) { _aggregators[i] = address(aggregators[currencyKeys[i]]); } flagList = _flags.getFlags(_aggregators); } else { flagList = new bool[](currencyKeys.length); } } function removeFromArray(bytes32 entry, bytes32[] storage array) internal returns (bool) { for (uint i = 0; i < array.length; i++) { if (array[i] == entry) { delete array[i]; // Copy the last key into the place of the one we just deleted // If there's only one key, this is array[0] = array[0]. // If we're deleting the last one, it's also a NOOP in the same way. array[i] = array[array.length - 1]; // Decrease the size of the array by one. array.length--; return true; } } return false; } function _formatAggregatorAnswer(bytes32 currencyKey, int256 rate) internal view returns (uint) { require(rate >= 0, "Negative rate not supported"); uint decimals = currencyKeyDecimals[currencyKey]; uint result = uint(rate); if (decimals == 0 || decimals == 18) { // do not convert for 0 (part of implicit interface), and not needed for 18 } else if (decimals < 18) { // increase precision to 18 uint multiplier = 10**(18 - decimals); // SafeMath not needed since decimals is small result = result.mul(multiplier); } else if (decimals > 18) { // decrease precision to 18 uint divisor = 10**(decimals - 18); // SafeMath not needed since decimals is small result = result.div(divisor); } return result; } function _getRateAndUpdatedTime(bytes32 currencyKey) internal view returns (RateAndUpdatedTime memory) { // sUSD rate is 1.0 if (currencyKey == sUSD) { return RateAndUpdatedTime({rate: uint216(SafeDecimalMath.unit()), time: 0}); } else { AggregatorV2V3Interface aggregator = aggregators[currencyKey]; if (aggregator != AggregatorV2V3Interface(0)) { // this view from the aggregator is the most gas efficient but it can throw when there's no data, // so let's call it low-level to suppress any reverts bytes memory payload = abi.encodeWithSignature("latestRoundData()"); // solhint-disable avoid-low-level-calls // slither-disable-next-line low-level-calls (bool success, bytes memory returnData) = address(aggregator).staticcall(payload); if (success) { (, int256 answer, , uint256 updatedAt, ) = abi.decode(returnData, (uint80, int256, uint256, uint256, uint80)); return RateAndUpdatedTime({ rate: uint216(_formatAggregatorAnswer(currencyKey, answer)), time: uint40(updatedAt) }); } // else return defaults, to avoid reverting in views } // else return defaults, to avoid reverting in views } } function _getCurrentRoundId(bytes32 currencyKey) internal view returns (uint) { if (currencyKey == sUSD) { return 0; } AggregatorV2V3Interface aggregator = aggregators[currencyKey]; if (aggregator != AggregatorV2V3Interface(0)) { return aggregator.latestRound(); } // else return defaults, to avoid reverting in views } function _getRateAndTimestampAtRound(bytes32 currencyKey, uint roundId) internal view returns (uint rate, uint time) { // short circuit sUSD if (currencyKey == sUSD) { // sUSD has no rounds, and 0 time is preferrable for "volatility" heuristics // which are used in atomic swaps and fee reclamation return (SafeDecimalMath.unit(), 0); } else { AggregatorV2V3Interface aggregator = aggregators[currencyKey]; if (aggregator != AggregatorV2V3Interface(0)) { // this view from the aggregator is the most gas efficient but it can throw when there's no data, // so let's call it low-level to suppress any reverts bytes memory payload = abi.encodeWithSignature("getRoundData(uint80)", roundId); // solhint-disable avoid-low-level-calls (bool success, bytes memory returnData) = address(aggregator).staticcall(payload); if (success) { (, int256 answer, , uint256 updatedAt, ) = abi.decode(returnData, (uint80, int256, uint256, uint256, uint80)); return (_formatAggregatorAnswer(currencyKey, answer), updatedAt); } // else return defaults, to avoid reverting in views } // else return defaults, to avoid reverting in views } } function _getRate(bytes32 currencyKey) internal view returns (uint256) { return _getRateAndUpdatedTime(currencyKey).rate; } function _getUpdatedTime(bytes32 currencyKey) internal view returns (uint256) { return _getRateAndUpdatedTime(currencyKey).time; } function _effectiveValueAndRates( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) internal view returns ( uint value, uint sourceRate, uint destinationRate ) { sourceRate = _getRate(sourceCurrencyKey); // If there's no change in the currency, then just return the amount they gave us if (sourceCurrencyKey == destinationCurrencyKey) { destinationRate = sourceRate; value = sourceAmount; } else { // Calculate the effective value by going from source -> USD -> destination destinationRate = _getRate(destinationCurrencyKey); // prevent divide-by 0 error (this happens if the dest is not a valid rate) if (destinationRate > 0) { value = sourceAmount.multiplyDecimalRound(sourceRate).divideDecimalRound(destinationRate); } } } function _rateIsStale(bytes32 currencyKey, uint _rateStalePeriod) internal view returns (bool) { // sUSD is a special case and is never stale (check before an SLOAD of getRateAndUpdatedTime) if (currencyKey == sUSD) { return false; } return _rateIsStaleWithTime(_rateStalePeriod, _getUpdatedTime(currencyKey)); } function _rateIsStaleWithTime(uint _rateStalePeriod, uint _time) internal view returns (bool) { return _time.add(_rateStalePeriod) < now; } function _rateIsFlagged(bytes32 currencyKey, FlagsInterface flags) internal view returns (bool) { // sUSD is a special case and is never invalid if (currencyKey == sUSD) { return false; } address aggregator = address(aggregators[currencyKey]); // when no aggregator or when the flags haven't been setup if (aggregator == address(0) || flags == FlagsInterface(0)) { return false; } return flags.getFlag(aggregator); } function _rateIsCircuitBroken(bytes32 currencyKey, uint curRate) internal view returns (bool) { return circuitBreaker().isInvalid(address(aggregators[currencyKey]), curRate); } function _notImplemented() internal pure { // slither-disable-next-line dead-code revert("Cannot be run on this layer"); } /* ========== EVENTS ========== */ event AggregatorAdded(bytes32 currencyKey, address aggregator); event AggregatorRemoved(bytes32 currencyKey, address aggregator); } // https://sips.synthetix.io/sips/sip-120/ // Uniswap V3 based DecPriceAggregator (unaudited) e.g. https://etherscan.io/address/0xf120f029ac143633d1942e48ae2dfa2036c5786c#code // https://github.com/sohkai/uniswap-v3-spot-twap-oracle // inteface: https://github.com/sohkai/uniswap-v3-spot-twap-oracle/blob/8f9777a6160a089c99f39f2ee297119ee293bc4b/contracts/interfaces/IDexPriceAggregator.sol // implementation: https://github.com/sohkai/uniswap-v3-spot-twap-oracle/blob/8f9777a6160a089c99f39f2ee297119ee293bc4b/contracts/DexPriceAggregatorUniswapV3.sol interface IDexPriceAggregator { function assetToAsset( address tokenIn, uint amountIn, address tokenOut, uint twapPeriod ) external view returns (uint amountOut); } // Inheritance // https://docs.synthetix.io/contracts/source/contracts/exchangerateswithdexpricing contract ExchangeRatesWithDexPricing is ExchangeRates { bytes32 public constant CONTRACT_NAME = "ExchangeRatesWithDexPricing"; bytes32 internal constant SETTING_DEX_PRICE_AGGREGATOR = "dexPriceAggregator"; constructor(address _owner, address _resolver) public ExchangeRates(_owner, _resolver) {} /* ========== ADDRESS RESOLVER CONFIGURATION ========== */ bytes32 private constant CONTRACT_DIRECT_INTEGRATION_MANAGER = "DirectIntegrationManager"; function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = ExchangeRates.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](1); newAddresses[0] = CONTRACT_DIRECT_INTEGRATION_MANAGER; addresses = combineArrays(existingAddresses, newAddresses); } /* ========== SETTERS ========== */ function setDexPriceAggregator(IDexPriceAggregator _dexPriceAggregator) external onlyOwner { flexibleStorage().setAddressValue( ExchangeRates.CONTRACT_NAME, SETTING_DEX_PRICE_AGGREGATOR, address(_dexPriceAggregator) ); emit DexPriceAggregatorUpdated(address(_dexPriceAggregator)); } /* ========== VIEWS ========== */ function directIntegrationManager() internal view returns (IDirectIntegrationManager) { return IDirectIntegrationManager(requireAndGetAddress(CONTRACT_DIRECT_INTEGRATION_MANAGER)); } function dexPriceAggregator() public view returns (IDexPriceAggregator) { return IDexPriceAggregator( flexibleStorage().getAddressValue(ExchangeRates.CONTRACT_NAME, SETTING_DEX_PRICE_AGGREGATOR) ); } // SIP-120 Atomic exchanges function effectiveAtomicValueAndRates( bytes32 sourceCurrencyKey, uint amount, bytes32 destinationCurrencyKey ) public view returns ( uint value, uint systemValue, uint systemSourceRate, uint systemDestinationRate ) { IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings = directIntegrationManager().getExchangeParameters(msg.sender, sourceCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings = directIntegrationManager().getExchangeParameters(msg.sender, destinationCurrencyKey); IDirectIntegrationManager.ParameterIntegrationSettings memory usdSettings = directIntegrationManager().getExchangeParameters(msg.sender, sUSD); return effectiveAtomicValueAndRates(sourceSettings, amount, destinationSettings, usdSettings); } // SIP-120 Atomic exchanges // Note that the returned systemValue, systemSourceRate, and systemDestinationRate are based on // the current system rate, which may not be the atomic rate derived from value / sourceAmount function effectiveAtomicValueAndRates( IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, uint sourceAmount, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory usdSettings ) public view returns ( uint value, uint systemValue, uint systemSourceRate, uint systemDestinationRate ) { (systemValue, systemSourceRate, systemDestinationRate) = _effectiveValueAndRates( sourceSettings.currencyKey, sourceAmount, destinationSettings.currencyKey ); bool usePureChainlinkPriceForSource = getPureChainlinkPriceForAtomicSwapsEnabled(sourceSettings.currencyKey); bool usePureChainlinkPriceForDest = getPureChainlinkPriceForAtomicSwapsEnabled(destinationSettings.currencyKey); uint sourceRate; uint destRate; // Handle the different scenarios that may arise when trading currencies with or without the PureChainlinkPrice set. // outlined here: https://sips.synthetix.io/sips/sip-198/#computation-methodology-in-atomic-pricing if (usePureChainlinkPriceForSource) { sourceRate = systemSourceRate; } else { sourceRate = _getMinValue( systemSourceRate, _getPriceFromDexAggregator(sourceSettings, usdSettings, sourceAmount) ); } if (usePureChainlinkPriceForDest) { destRate = systemDestinationRate; } else { destRate = _getMaxValue( systemDestinationRate, _getPriceFromDexAggregator(usdSettings, destinationSettings, sourceAmount) ); } value = sourceAmount.mul(sourceRate).div(destRate); } function _getMinValue(uint x, uint y) internal pure returns (uint) { return x < y ? x : y; } function _getMaxValue(uint x, uint y) internal pure returns (uint) { return x > y ? x : y; } /// @notice Retrieve the TWAP (time-weighted average price) of an asset from its Uniswap V3-equivalent pool /// @dev By default, the TWAP oracle 'hops' through the wETH pool. This can be overridden. See DexPriceAggregator for more information. /// @dev The TWAP oracle doesn't take into account variable slippage due to trade amounts, as Uniswap's OracleLibary doesn't cross ticks based on their liquidity. See: https://docs.uniswap.org/protocol/concepts/V3-overview/oracle#deriving-price-from-a-tick /// @dev One of `sourceCurrencyKey` or `destCurrencyKey` should be sUSD. There are two parameters to indicate directionality. Because this function returns "price", if the source is sUSD, the result will be flipped. /// @param sourceSettings The settings data for the source token /// @param destinationSettings The settings data for the destination token /// @param amount The amount of the asset we're interested in /// @return The price of the asset function _getPriceFromDexAggregator( IDirectIntegrationManager.ParameterIntegrationSettings memory sourceSettings, IDirectIntegrationManager.ParameterIntegrationSettings memory destinationSettings, uint amount ) internal view returns (uint) { require(amount != 0, "Amount must be greater than 0"); require( sourceSettings.currencyKey == sUSD || destinationSettings.currencyKey == sUSD, "Atomic swaps must go through sUSD" ); IERC20 sourceEquivalent = IERC20(sourceSettings.atomicEquivalentForDexPricing); require(address(sourceEquivalent) != address(0), "No atomic equivalent for source"); IERC20 destEquivalent = IERC20(destinationSettings.atomicEquivalentForDexPricing); require(address(destEquivalent) != address(0), "No atomic equivalent for dest"); uint result = _dexPriceDestinationValue( IDexPriceAggregator(sourceSettings.dexPriceAggregator), sourceEquivalent, destEquivalent, amount, sourceSettings .atomicTwapWindow ) .mul(SafeDecimalMath.unit()) .div(amount); require(result != 0, "Result must be greater than 0"); return destinationSettings.currencyKey == "sUSD" ? result : SafeDecimalMath.unit().divideDecimalRound(result); } function _dexPriceDestinationValue( IDexPriceAggregator dexAggregator, IERC20 sourceEquivalent, IERC20 destEquivalent, uint sourceAmount, uint twapWindow ) internal view returns (uint) { // Normalize decimals in case equivalent asset uses different decimals from internal unit uint sourceAmountInEquivalent = (sourceAmount.mul(10**uint(sourceEquivalent.decimals()))).div(SafeDecimalMath.unit()); require(address(dexAggregator) != address(0), "dex aggregator address is 0"); require(twapWindow != 0, "Uninitialized atomic twap window"); uint twapValueInEquivalent = dexAggregator.assetToAsset( address(sourceEquivalent), sourceAmountInEquivalent, address(destEquivalent), twapWindow ); require(twapValueInEquivalent > 0, "dex price returned 0"); // Similar to source amount, normalize decimals back to internal unit for output amount return (twapValueInEquivalent.mul(SafeDecimalMath.unit())).div(10**uint(destEquivalent.decimals())); } function synthTooVolatileForAtomicExchange(bytes32 currencyKey) public view returns (bool) { IDirectIntegrationManager.ParameterIntegrationSettings memory settings = directIntegrationManager().getExchangeParameters(msg.sender, currencyKey); return synthTooVolatileForAtomicExchange(settings); } function synthTooVolatileForAtomicExchange(IDirectIntegrationManager.ParameterIntegrationSettings memory settings) public view returns (bool) { // sUSD is a special case and is never volatile if (settings.currencyKey == "sUSD") return false; uint considerationWindow = settings.atomicVolatilityConsiderationWindow; uint updateThreshold = settings.atomicVolatilityUpdateThreshold; if (considerationWindow == 0 || updateThreshold == 0) { // If either volatility setting is not set, never judge an asset to be volatile return false; } // Go back through the historical oracle update rounds to see if there have been more // updates in the consideration window than the allowed threshold. // If there have, consider the asset volatile--by assumption that many close-by oracle // updates is a good proxy for price volatility. uint considerationWindowStart = block.timestamp.sub(considerationWindow); uint roundId = _getCurrentRoundId(settings.currencyKey); for (updateThreshold; updateThreshold > 0; updateThreshold--) { (uint rate, uint time) = _getRateAndTimestampAtRound(settings.currencyKey, roundId); if (time != 0 && time < considerationWindowStart) { // Round was outside consideration window so we can stop querying further rounds return false; } else if (rate == 0 || time == 0) { // Either entire round or a rate inside consideration window was not available // Consider the asset volatile break; } if (roundId == 0) { // Not enough historical data to continue further // Consider the asset volatile break; } roundId--; } return true; } /* ========== EVENTS ========== */ event DexPriceAggregatorUpdated(address newDexPriceAggregator); }
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":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"aggregator","type":"address"}],"name":"AggregatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"aggregator","type":"address"}],"name":"AggregatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newDexPriceAggregator","type":"address"}],"name":"DexPriceAggregatorUpdated","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"},{"constant":true,"inputs":[],"name":"CONTRACT_NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"aggregatorAddress","type":"address"}],"name":"addAggregator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"aggregatorKeys","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"aggregatorWarningFlags","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"aggregators","outputs":[{"internalType":"contract AggregatorV2V3Interface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"anyRateIsInvalid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"},{"internalType":"uint256[]","name":"roundIds","type":"uint256[]"}],"name":"anyRateIsInvalidAtRound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"aggregator","type":"address"}],"name":"currenciesUsingAggregator","outputs":[{"internalType":"bytes32[]","name":"currencies","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"currencyKeyDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dexPriceAggregator","outputs":[{"internalType":"contract IDexPriceAggregator","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"effectiveAtomicValueAndRates","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"systemValue","type":"uint256"},{"internalType":"uint256","name":"systemSourceRate","type":"uint256"},{"internalType":"uint256","name":"systemDestinationRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"dexPriceAggregator","type":"address"},{"internalType":"address","name":"atomicEquivalentForDexPricing","type":"address"},{"internalType":"uint256","name":"atomicExchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"atomicTwapWindow","type":"uint256"},{"internalType":"uint256","name":"atomicMaxVolumePerBlock","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityConsiderationWindow","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"exchangeMaxDynamicFee","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeRounds","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeWeightDecay","type":"uint256"}],"internalType":"struct IDirectIntegrationManager.ParameterIntegrationSettings","name":"sourceSettings","type":"tuple"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"components":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"dexPriceAggregator","type":"address"},{"internalType":"address","name":"atomicEquivalentForDexPricing","type":"address"},{"internalType":"uint256","name":"atomicExchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"atomicTwapWindow","type":"uint256"},{"internalType":"uint256","name":"atomicMaxVolumePerBlock","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityConsiderationWindow","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"exchangeMaxDynamicFee","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeRounds","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeWeightDecay","type":"uint256"}],"internalType":"struct IDirectIntegrationManager.ParameterIntegrationSettings","name":"destinationSettings","type":"tuple"},{"components":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"dexPriceAggregator","type":"address"},{"internalType":"address","name":"atomicEquivalentForDexPricing","type":"address"},{"internalType":"uint256","name":"atomicExchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"atomicTwapWindow","type":"uint256"},{"internalType":"uint256","name":"atomicMaxVolumePerBlock","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityConsiderationWindow","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"exchangeMaxDynamicFee","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeRounds","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeWeightDecay","type":"uint256"}],"internalType":"struct IDirectIntegrationManager.ParameterIntegrationSettings","name":"usdSettings","type":"tuple"}],"name":"effectiveAtomicValueAndRates","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"systemValue","type":"uint256"},{"internalType":"uint256","name":"systemSourceRate","type":"uint256"},{"internalType":"uint256","name":"systemDestinationRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"effectiveValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"effectiveValueAndRates","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"sourceRate","type":"uint256"},{"internalType":"uint256","name":"destinationRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"roundIdForSrc","type":"uint256"},{"internalType":"uint256","name":"roundIdForDest","type":"uint256"}],"name":"effectiveValueAndRatesAtRound","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"sourceRate","type":"uint256"},{"internalType":"uint256","name":"destinationRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"getCurrentRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"startingRoundId","type":"uint256"},{"internalType":"uint256","name":"startingTimestamp","type":"uint256"},{"internalType":"uint256","name":"timediff","type":"uint256"}],"name":"getLastRoundIdBeforeElapsedSecs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"lastRateUpdateTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"lastRateUpdateTimesForCurrencies","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateAndInvalid","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"bool","name":"isInvalid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"rateAndTimestampAtRound","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateAndUpdatedTime","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateForCurrency","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateIsFlagged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateIsInvalid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateIsStale","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"rateStalePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"rateWithSafetyChecks","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"bool","name":"broken","type":"bool"},{"internalType":"bool","name":"staleOrInvalid","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"ratesAndInvalidForCurrencies","outputs":[{"internalType":"uint256[]","name":"rates","type":"uint256[]"},{"internalType":"bool","name":"anyRateInvalid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"numRounds","type":"uint256"},{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"ratesAndUpdatedTimeForCurrencyLastNRounds","outputs":[{"internalType":"uint256[]","name":"rates","type":"uint256[]"},{"internalType":"uint256[]","name":"times","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32[]","name":"currencyKeys","type":"bytes32[]"}],"name":"ratesForCurrencies","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"removeAggregator","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":"contract IDexPriceAggregator","name":"_dexPriceAggregator","type":"address"}],"name":"setDexPriceAggregator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"synthTooVolatileForAtomicExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"address","name":"dexPriceAggregator","type":"address"},{"internalType":"address","name":"atomicEquivalentForDexPricing","type":"address"},{"internalType":"uint256","name":"atomicExchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"atomicTwapWindow","type":"uint256"},{"internalType":"uint256","name":"atomicMaxVolumePerBlock","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityConsiderationWindow","type":"uint256"},{"internalType":"uint256","name":"atomicVolatilityUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"},{"internalType":"uint256","name":"exchangeMaxDynamicFee","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeRounds","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeThreshold","type":"uint256"},{"internalType":"uint256","name":"exchangeDynamicFeeWeightDecay","type":"uint256"}],"internalType":"struct IDirectIntegrationManager.ParameterIntegrationSettings","name":"settings","type":"tuple"}],"name":"synthTooVolatileForAtomicExchange","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620047bc380380620047bc833981016040819052620000349162000100565b81818080836001600160a01b0381166200006b5760405162461bcd60e51b81526004016200006290620001bc565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91620000b891849062000196565b60405180910390a150600280546001600160a01b0319166001600160a01b039290921691909117905550620002179350505050565b8051620000fa81620001fd565b92915050565b600080604083850312156200011457600080fd5b6000620001228585620000ed565b92505060206200013585828601620000ed565b9150509250929050565b6200014a81620001e9565b82525050565b6200014a81620001d7565b60006200016a601983620001ce565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b60408101620001a682856200013f565b620001b5602083018462000150565b9392505050565b60208082528101620000fa816200015b565b90815260200190565b60006001600160a01b038216620000fa565b6000620000fa826000620000fa82620001d7565b6200020881620001d7565b81146200021457600080fd5b50565b61459580620002276000396000f3fe608060405234801561001057600080fd5b50600436106102685760003560e01c8063614d08f8116101515780638da5cb5b116100c3578063c8e5bbd511610087578063c8e5bbd514610563578063ce8480ea14610584578063d89ee86114610597578063ed762450146105aa578063fce132f9146105cb578063fdadbc7e146105de57610268565b80638da5cb5b1461050d5780639eab4a3714610515578063ac82f6081461051d578063b295ad3414610530578063c2c8a6761461055057610268565b806374eded391161011557806374eded39146104b157806379ba5097146104c45780637a018a1e146104cc5780638295016a146104df5780638661cc7b146104f2578063899ffef41461050557610268565b8063614d08f814610459578063654a60ac146104615780636ce66c80146104745780637103353e1461049657806374185360146104a957610268565b80632528f0fe116101ea57806338aa1b99116101ae57806338aa1b99146103e25780633f0e084f146103f55780634308a94f146104085780634c36b837146104295780634f72def61461043e57806353a47bb71461045157610268565b80632528f0fe146103815780632678df961461039457806326bd30fa146103b45780632af64bd3146103c75780632bed9e0c146103cf57610268565b80630a7d36d1116102315780630a7d36d1146103105780630c71cd23146103235780630ee4951b14610344578063109e46a2146103595780631627540c1461036c57610268565b80629919c01461026d578063045056f81461029657806304f3bcec146102b8578063055286e0146102cd57806305a046e5146102f0575b600080fd5b61028061027b3660046135ff565b6105f1565b60405161028d919061419b565b60405180910390f35b6102a96102a43660046135ff565b61060c565b60405161028d93929190614395565b6102c061077f565b60405161028d919061421b565b6102e06102db366004613687565b61078e565b60405161028d94939291906143e5565b6103036102fe36600461352f565b61096b565b60405161028d9190614145565b61028061031e36600461352f565b6109ed565b6103366103313660046135ff565b610b16565b60405161028d92919061437a565b61034c610bb3565b60405161028d91906141a9565b61034c610367366004613749565b610bc3565b61037f61037a3660046134be565b610c06565b005b61028061038f3660046135ff565b610c64565b6103a76103a23660046134be565b610c70565b60405161028d9190614134565b6102e06103c2366004613806565b610d24565b610280610de3565b61037f6103dd3660046135ff565b610efa565b6102806103f03660046135ff565b610fb7565b61037f61040336600461361d565b610fc5565b61041b6104163660046135ff565b6111cc565b60405161028d9291906141c5565b610431611204565b60405161028d9190614081565b61034c61044c3660046135ff565b61120e565b61043161122c565b61034c61123b565b61034c61046f366004613687565b61125f565b6104876104823660046136d4565b611277565b60405161028d939291906143bd565b6102c06104a43660046135ff565b6112dc565b61037f6112f7565b61037f6104bf3660046137aa565b61144d565b61037f611512565b61034c6104da3660046135ff565b6115ae565b6104876104ed366004613687565b6115b9565b6102806105003660046135ff565b6115d9565b6103a761167b565b6104316116f2565b6102c0611701565b61034c61052b3660046135ff565b6117ad565b61054361053e3660046135ff565b6117c8565b60405161028d919061440d565b61030361055e36600461352f565b6117dd565b61057661057136600461352f565b611855565b60405161028d92919061417b565b61034c6105923660046135ff565b6119a5565b6102806105a5366004613571565b6119b0565b6105bd6105b8366004613687565b611af5565b60405161028d929190614156565b6102806105d93660046137c8565b611bd3565b61041b6105ec366004613657565b611cb6565b6000610604826105ff611ccf565b611d79565b90505b919050565b600081815260046020526040812054819081906001600160a01b0316631cd554d160e21b85148061064557506001600160a01b03811615155b61066a5760405162461bcd60e51b8152600401610661906142ca565b60405180910390fd5b610672613083565b61067b86611da4565b9050631cd554d160e21b8614156106a657516001600160d81b03169350600092508291506107789050565b80516001600160d81b031694506106bb611f6e565b815160405163413caeb560e01b81526001600160a01b03929092169163413caeb5916106ec918691906004016140c5565b602060405180830381600087803b15801561070657600080fd5b505af115801561071a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061073e91908101906135e1565b935061075c61074b611ccf565b826020015164ffffffffff16611f8a565b8061077357506107738661076e611fa5565b612006565b925050505b9193909250565b6002546001600160a01b031681565b60008060008061079c61309a565b6107a46120d6565b6001600160a01b031663697b659b338a6040518363ffffffff1660e01b81526004016107d192919061408f565b6101a06040518083038186803b1580156107ea57600080fd5b505afa1580156107fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061082291908101906137e7565b905061082c61309a565b6108346120d6565b6001600160a01b031663697b659b33896040518363ffffffff1660e01b815260040161086192919061408f565b6101a06040518083038186803b15801561087a57600080fd5b505afa15801561088e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b291908101906137e7565b90506108bc61309a565b6108c46120d6565b6001600160a01b031663697b659b33631cd554d160e21b6040518363ffffffff1660e01b81526004016108f892919061408f565b6101a06040518083038186803b15801561091157600080fd5b505afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061094991908101906137e7565b9050610957838a8484610d24565b965096509650965050505093509350935093565b6060808383905060405190808252806020026020018201604052801561099b578160200160208202803883390190505b50905060005b838110156109e3576109c48585838181106109b857fe5b905060200201356120fc565b8282815181106109d057fe5b60209081029190910101526001016109a1565b5090505b92915050565b6000806109f8611ccf565b90506060610a3885858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061211892505050565b905060005b84811015610b0a57631cd554d160e21b868683818110610a5957fe5b905060200201351415610a6b57610b02565b610a73613083565b610a8e878784818110610a8257fe5b90506020020135611da4565b9050828281518110610a9c57fe5b602002602001015180610abf5750610abf84826020015164ffffffffff16611f8a565b80610aee5750610aee878784818110610ad457fe5b9050602002013582600001516001600160d81b0316612293565b15610b005760019450505050506109e7565b505b600101610a3d565b50600095945050505050565b600080610b21613083565b610b2a84611da4565b9050631cd554d160e21b841415610b5057516001600160d81b0316915060009050610bae565b8051610b6e610b5d611ccf565b836020015164ffffffffff16611f8a565b80610b805750610b808561076e611fa5565b80610b9d5750610b9d8583600001516001600160d81b0316612293565b6001600160d81b0390911693509150505b915091565b6000610bbd611ccf565b90505b90565b600083815b610bd5878360010161232d565b915050801580610be6575083850181115b15610bf357509050610bfe565b600190910190610bc8565b949350505050565b610c0e6124cf565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290610c59908390614081565b60405180910390a150565b600080610bfe83610b16565b600654604080518281526020808402820101909152606091600091908015610ca2578160200160208202803883390190505b50915060005b600654811015610d1d57600060068281548110610cc157fe5b600091825260208083209091015480835260049091526040909120549091506001600160a01b039081169086161415610d145780848480600101955081518110610d0757fe5b6020026020010181815250505b50600101610ca8565b5050919050565b600080600080610d3d88600001518888600001516124fb565b8a519295509093509150600090610d539061254d565b90506000610d64886000015161254d565b90506000808315610d7757859150610d8e565b610d8b86610d868e8c8f61262d565b612841565b91505b8215610d9b575083610db2565b610daf85610daa8b8d8f61262d565b612857565b90505b610dd281610dc68d8563ffffffff61286616565b9063ffffffff6128a016565b975050505050945094509450949050565b60006060610def61167b565b905060005b8151811015610ef1576000828281518110610e0b57fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a72190610e5c9085906004016141a9565b60206040518083038186803b158015610e7457600080fd5b505afa158015610e88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610eac91908101906134dc565b6001600160a01b0316141580610ed757506000818152600360205260409020546001600160a01b0316155b15610ee85760009350505050610bc0565b50600101610df4565b50600191505090565b610f026124cf565b6000818152600460205260409020546001600160a01b031680610f375760405162461bcd60e51b81526004016106619061436a565b600082815260046020908152604080832080546001600160a01b031916905560059091528120805460ff19169055610f708360066128d5565b90508015610fb2577fec70e890fc7db7de4059b114c9093a1f41283d18ffcfbcac45566feea4d4f7778383604051610fa99291906141b7565b60405180910390a15b505050565b60006106048261076e611fa5565b610fcd6124cf565b60008190506000816001600160a01b031663668a0f026040518163ffffffff1660e01b815260040160206040518083038186803b15801561100d57600080fd5b505afa158015611021573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611045919081019061385f565b10156110635760405162461bcd60e51b81526004016106619061434a565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561109e57600080fd5b505afa1580156110b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110d691908101906138e5565b9050601b8160ff1611156110fc5760405162461bcd60e51b8152600401610661906142ba565b6000848152600460205260409020546001600160a01b031661114e57600680546001810182556000919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f018490555b600084815260046020908152604080832080546001600160a01b0319166001600160a01b038716179055600590915290819020805460ff191660ff8416179055517f0bcae573430f69c5361e5d76534d3f61d2d803958778680cd74be9dc6299bc63906111be90869085906141b7565b60405180910390a150505050565b6000806111d7613083565b6111e084611da4565b80516020909101516001600160d81b03909116935064ffffffffff16915050915091565b6000610bbd611fa5565b6006818154811061121b57fe5b600091825260209091200154905081565b6001546001600160a01b031681565b7f45786368616e676552617465735769746844657850726963696e67000000000081565b600061126c8484846124fb565b509095945050505050565b6000806000611286888661232d565b5091508786141561129b5750859150806112d1565b6112a5868561232d565b50905080156112d1576112ce816112c2898563ffffffff61297916565b9063ffffffff61298e16565b92505b955095509592505050565b6004602052600090815260409020546001600160a01b031681565b606061130161167b565b905060005b815181101561144957600082828151811061131d57fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d01838460405160200161135f9190614076565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161138b9291906141fb565b60206040518083038186803b1580156113a357600080fd5b505afa1580156113b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113db91908101906134dc565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa689061143790849084906141b7565b60405180910390a15050600101611306565b5050565b6114556124cf565b61145d6129a3565b6001600160a01b0316634dca09786c45786368616e6765526174657360981b713232bc283934b1b2a0b3b3b932b3b0ba37b960711b846040518463ffffffff1660e01b81526004016114b1939291906141d3565b600060405180830381600087803b1580156114cb57600080fd5b505af11580156114df573d6000803e3d6000fd5b505050507f8a51d16f378c74938a4b9290afe425bbfba62f05aa9d27bff5e892f62696f76081604051610c599190614081565b6001546001600160a01b0316331461153c5760405162461bcd60e51b81526004016106619061425a565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9261157f926001600160a01b03918216929116906140aa565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000610604826129c0565b60008060006115c98686866124fb565b9250925092505b93509350939050565b60006115e361309a565b6115eb6120d6565b6001600160a01b031663697b659b33856040518363ffffffff1660e01b815260040161161892919061408f565b6101a06040518083038186803b15801561163157600080fd5b505afa158015611645573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061166991908101906137e7565b905061167481611bd3565b9392505050565b606080611686612a70565b6040805160018082528183019092529192506060919060208083019080388339019050509050772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b816000815181106116d557fe5b6020026020010181815250506116eb8282612ac0565b9250505090565b6000546001600160a01b031681565b600061170b6129a3565b6001600160a01b0316639ee5955a6c45786368616e6765526174657360981b713232bc283934b1b2a0b3b3b932b3b0ba37b960711b6040518363ffffffff1660e01b815260040161175d9291906141c5565b60206040518083038186803b15801561177557600080fd5b505afa158015611789573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bbd91908101906134dc565b60006117b882611da4565b516001600160d81b031692915050565b60056020526000908152604090205460ff1681565b6060808383905060405190808252806020026020018201604052801561180d578160200160208202803883390190505b50905060005b838110156109e35761183685858381811061182a57fe5b905060200201356117ad565b82828151811061184257fe5b6020908102919091010152600101611813565b6060600083839050604051908082528060200260200182016040528015611886578160200160208202803883390190505b5091506000611893611ccf565b905060606118d386868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061211892505050565b905060005b8581101561199b576118e8613083565b6118f7888884818110610a8257fe5b905080600001516001600160d81b031686838151811061191357fe5b602002602001018181525050841580156119465750631cd554d160e21b88888481811061193c57fe5b9050602002013514155b156119925782828151811061195757fe5b60200260200101518061197a575061197a84826020015164ffffffffff16611f8a565b8061198f575061198f888884818110610ad457fe5b94505b506001016118d8565b5050509250929050565b6000610604826120fc565b60008184146119d15760405162461bcd60e51b81526004016106619061435a565b60006119db611ccf565b90506060611a1b87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061211892505050565b905060005b86811015611ae757631cd554d160e21b888883818110611a3c57fe5b905060200201351415611a4e57611adf565b600080611a7f8a8a85818110611a6057fe5b90506020020135898986818110611a7357fe5b9050602002013561232d565b91509150838381518110611a8f57fe5b602002602001015180611aa75750611aa78582611f8a565b80611ac95750611ac98a8a85818110611abc57fe5b9050602002013583612293565b15611adc57600195505050505050610bfe565b50505b600101611a20565b506000979650505050505050565b60608083604051908082528060200260200182016040528015611b22578160200160208202803883390190505b50915083604051908082528060200260200182016040528015611b4f578160200160208202803883390190505b50905060008311611b6857611b63856129c0565b611b6a565b825b925060005b84811015611bc957611b81868561232d565b848381518110611b8d57fe5b60200260200101848481518110611ba057fe5b60209081029190910101919091525283611bba5750611bcb565b60001990930192600101611b6f565b505b935093915050565b8051600090631cd554d160e21b1415611bee57506000610607565b60c082015160e0830151811580611c03575080155b15611c1357600092505050610607565b6000611c25428463ffffffff612b7c16565b90506000611c3686600001516129c0565b90505b8215611caa57600080611c5088600001518461232d565b9150915080600014158015611c6457508381105b15611c785760009650505050505050610607565b811580611c83575080155b15611c8f575050611caa565b82611c9b575050611caa565b50506000199283019201611c39565b50600195945050505050565b600080611cc3848461232d565b915091505b9250929050565b6000611cd96129a3565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6e1c985d1954dd185b1954195c9a5bd9608a1b6040518363ffffffff1660e01b8152600401611d299291906141c5565b60206040518083038186803b158015611d4157600080fd5b505afa158015611d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bbd919081019061385f565b6000631cd554d160e21b831415611d92575060006109e7565b61167482611d9f856120fc565b611f8a565b611dac613083565b631cd554d160e21b821415611e5c5760405180604001604052807384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611e0a57600080fd5b505af4158015611e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e42919081019061385f565b6001600160d81b0316815260006020909101529050610607565b6000828152600460205260409020546001600160a01b03168015611f685760408051600481526024810182526020810180516001600160e01b0316633fabe5a360e21b17905290516000906060906001600160a01b03851690611ec090859061404a565b600060405180830381855afa9150503d8060008114611efb576040519150601f19603f3d011682016040523d82523d6000602084013e611f00565b606091505b50915091508115611f645760008082806020019051611f22919081019061387d565b509350509250506040518060400160405280611f3e8a85612ba4565b6001600160d81b031681526020018264ffffffffff168152509650505050505050610607565b5050505b50919050565b6000610bbd6d21b4b931bab4ba213932b0b5b2b960911b612c44565b600042611f9d838563ffffffff612ca116565b109392505050565b6000611faf6129a3565b6001600160a01b0316639ee5955a6d53797374656d53657474696e677360901b7561676772656761746f725761726e696e67466c61677360501b6040518363ffffffff1660e01b815260040161175d9291906141c5565b6000631cd554d160e21b83141561201f575060006109e7565b6000838152600460205260409020546001600160a01b031680158061204b57506001600160a01b038316155b1561205a5760009150506109e7565b604051631abf23ff60e11b81526001600160a01b0384169063357e47fe90612086908490600401614081565b60206040518083038186803b15801561209e57600080fd5b505afa1580156120b2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bfe91908101906135e1565b6000610bbd772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b612c44565b600061210782611da4565b6020015164ffffffffff1692915050565b60606000612124611fa5565b90506001600160a01b038116156122605760608351604051908082528060200260200182016040528015612162578160200160208202803883390190505b50905060005b84518110156121d7576004600086838151811061218157fe5b6020026020010151815260200190815260200160002060009054906101000a90046001600160a01b03168282815181106121b757fe5b6001600160a01b0390921660209283029190910190910152600101612168565b50604051631f5c8f2b60e21b81526001600160a01b03831690637d723cac90612204908490600401614123565b60006040518083038186803b15801561221c57600080fd5b505afa158015612230573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261225891908101906134fa565b925050611f68565b825160405190808252806020026020018201604052801561228b578160200160208202803883390190505b509392505050565b600061229d611f6e565b6000848152600460208190526040918290205491516318b844ad60e01b81526001600160a01b03938416936318b844ad936122dd939116918791016140e0565b60206040518083038186803b1580156122f557600080fd5b505afa158015612309573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061167491908101906135e1565b600080631cd554d160e21b8414156123c6577384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561238357600080fd5b505af4158015612397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123bb919081019061385f565b915060009050611cc8565b6000848152600460205260409020546001600160a01b031680156124c7576060846040516024016123f791906141a9565b60408051601f198184030181529181526020820180516001600160e01b0316639a6fc8f560e01b179052519091506000906060906001600160a01b0385169061244190859061404a565b600060405180830381855afa9150503d806000811461247c576040519150601f19603f3d011682016040523d82523d6000602084013e612481565b606091505b509150915081156124c357600080828060200190516124a3919081019061387d565b509350509250506124b48a83612ba4565b97509550611cc8945050505050565b5050505b509250929050565b6000546001600160a01b031633146124f95760405162461bcd60e51b8152600401610661906142fa565b565b6000806000612509866117ad565b91508386141561251d5750839150806115d0565b612526846117ad565b905080156115d057612542816112c2878563ffffffff61297916565b925093509350939050565b60006125576129a3565b6001600160a01b031663d994502d6d53797374656d53657474696e677360901b7f70757265436861696e6c696e6b466f7241746f6d696373456e61626c65640000856040516020016125aa929190614024565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b81526004016125dd9291906141c5565b60206040518083038186803b1580156125f557600080fd5b505afa158015612609573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060491908101906135e1565b60008161264c5760405162461bcd60e51b8152600401610661906142aa565b8351631cd554d160e21b148061266957508251631cd554d160e21b145b6126855760405162461bcd60e51b81526004016106619061424a565b60408401516001600160a01b0381166126b05760405162461bcd60e51b81526004016106619061423a565b60408401516001600160a01b0381166126db5760405162461bcd60e51b81526004016106619061431a565b600061278185610dc67384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561272857600080fd5b505af415801561273c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612760919081019061385f565b6127758b6020015188888c8f60800151612cc6565b9063ffffffff61286616565b9050806127a05760405162461bcd60e51b81526004016106619061433a565b8551631cd554d160e21b146128345761282f817384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b1580156127f757600080fd5b505af415801561280b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112c2919081019061385f565b612836565b805b979650505050505050565b60008183106128505781611674565b5090919050565b60008183116128505781611674565b600082612875575060006109e7565b8282028284828161288257fe5b04146116745760405162461bcd60e51b81526004016106619061430a565b60008082116128c15760405162461bcd60e51b8152600401610661906142ea565b60008284816128cc57fe5b04949350505050565b6000805b825481101561296f57838382815481106128ef57fe5b906000526020600020015414156129675782818154811061290c57fe5b600091825260208220015582548390600019810190811061292957fe5b906000526020600020015483828154811061294057fe5b600091825260209091200155825461295c846000198301613117565b5060019150506109e7565b6001016128d9565b5060009392505050565b60006116748383670de0b6b3a7640000612fcf565b60006116748383670de0b6b3a764000061300c565b6000610bbd6e466c657869626c6553746f7261676560881b612c44565b6000631cd554d160e21b8214156129d957506000610607565b6000828152600460205260409020546001600160a01b03168015611f6857806001600160a01b031663668a0f026040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3057600080fd5b505afa158015612a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a68919081019061385f565b915050610607565b606080612a7b613032565b60408051600180825281830190925291925060609190602080830190803883390190505090506d21b4b931bab4ba213932b0b5b2b960911b816000815181106116d557fe5b60608151835101604051908082528060200260200182016040528015612af0578160200160208202803883390190505b50905060005b8351811015612b3257838181518110612b0b57fe5b6020026020010151828281518110612b1f57fe5b6020908102919091010152600101612af6565b5060005b8251811015612b7557828181518110612b4b57fe5b6020026020010151828286510181518110612b6257fe5b6020908102919091010152600101612b36565b5092915050565b600082821115612b9e5760405162461bcd60e51b8152600401610661906142da565b50900390565b600080821215612bc65760405162461bcd60e51b81526004016106619061426a565b60008381526005602052604090205460ff1682811580612be65750816012145b15612bf057610bfe565b6012821015612c19576012829003600a0a612c11828263ffffffff61286616565b915050610bfe565b6012821115610bfe576011198201600a0a612c3a828263ffffffff6128a016565b9695505050505050565b60008181526003602090815260408083205490516001600160a01b039091169182151591612c7491869101614056565b60405160208183030381529060405290612b755760405162461bcd60e51b81526004016106619190614229565b6000828201838110156116745760405162461bcd60e51b81526004016106619061428a565b600080612dcf7384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612d1057600080fd5b505af4158015612d24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d48919081019061385f565b610dc6886001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8457600080fd5b505afa158015612d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612dbc91908101906138e5565b879060ff16600a0a63ffffffff61286616565b90506001600160a01b038716612df75760405162461bcd60e51b81526004016106619061432a565b82612e145760405162461bcd60e51b81526004016106619061429a565b604051637c66194960e01b81526000906001600160a01b03891690637c66194990612e49908a9086908b908a906004016140ee565b60206040518083038186803b158015612e6157600080fd5b505afa158015612e75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e99919081019061385f565b905060008111612ebb5760405162461bcd60e51b81526004016106619061427a565b612fc1866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612ef757600080fd5b505afa158015612f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f2f91908101906138e5565b60ff16600a0a610dc67384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7c57600080fd5b505af4158015612f90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612fb4919081019061385f565b849063ffffffff61286616565b925050505b95945050505050565b600080600a8304612fe6868663ffffffff61286616565b81612fed57fe5b0490506005600a825b061061300057600a015b600a9004949350505050565b60008061302684610dc687600a870263ffffffff61286616565b90506005600a82612ff6565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b8160008151811061307457fe5b60200260200101818152505090565b604080518082019091526000808252602082015290565b604051806101a001604052806000801916815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815481835581811115610fb257600083815260209020610fb2918101908301610bc091905b80821115613150576000815560010161313c565b5090565b80356109e78161450e565b80516109e78161450e565b600082601f83011261317b57600080fd5b815161318e61318982614442565b61441b565b915081818352602084019350602081019050838560208402820111156131b357600080fd5b60005b838110156131df57816131c9888261322b565b84525060209283019291909101906001016131b6565b5050505092915050565b60008083601f8401126131fb57600080fd5b50813567ffffffffffffffff81111561321357600080fd5b602083019150836020820283011115611cc857600080fd5b80516109e781614525565b80356109e78161452e565b80516109e78161452e565b80356109e781614537565b60006101a0828403121561326a57600080fd5b6132756101a061441b565b905060006132838484613236565b825250602061329484848301613154565b60208301525060406132a884828501613154565b60408301525060606132bc84828501613236565b60608301525060806132d084828501613236565b60808301525060a06132e484828501613236565b60a08301525060c06132f884828501613236565b60c08301525060e061330c84828501613236565b60e08301525061010061332184828501613236565b6101008301525061012061333784828501613236565b6101208301525061014061334d84828501613236565b6101408301525061016061336384828501613236565b6101608301525061018061337984828501613236565b6101808301525092915050565b60006101a0828403121561339957600080fd5b6133a46101a061441b565b905060006133b28484613241565b82525060206133c38484830161315f565b60208301525060406133d78482850161315f565b60408301525060606133eb84828501613241565b60608301525060806133ff84828501613241565b60808301525060a061341384828501613241565b60a08301525060c061342784828501613241565b60c08301525060e061343b84828501613241565b60e08301525061010061345084828501613241565b6101008301525061012061346684828501613241565b6101208301525061014061347c84828501613241565b6101408301525061016061349284828501613241565b6101608301525061018061337984828501613241565b80516109e781614549565b80516109e781614540565b6000602082840312156134d057600080fd5b6000610bfe8484613154565b6000602082840312156134ee57600080fd5b6000610bfe848461315f565b60006020828403121561350c57600080fd5b815167ffffffffffffffff81111561352357600080fd5b610bfe8482850161316a565b6000806020838503121561354257600080fd5b823567ffffffffffffffff81111561355957600080fd5b613565858286016131e9565b92509250509250929050565b6000806000806040858703121561358757600080fd5b843567ffffffffffffffff81111561359e57600080fd5b6135aa878288016131e9565b9450945050602085013567ffffffffffffffff8111156135c957600080fd5b6135d5878288016131e9565b95989497509550505050565b6000602082840312156135f357600080fd5b6000610bfe848461322b565b60006020828403121561361157600080fd5b6000610bfe8484613236565b6000806040838503121561363057600080fd5b600061363c8585613236565b925050602061364d85828601613154565b9150509250929050565b6000806040838503121561366a57600080fd5b60006136768585613236565b925050602061364d85828601613236565b60008060006060848603121561369c57600080fd5b60006136a88686613236565b93505060206136b986828701613236565b92505060406136ca86828701613236565b9150509250925092565b600080600080600060a086880312156136ec57600080fd5b60006136f88888613236565b955050602061370988828901613236565b945050604061371a88828901613236565b935050606061372b88828901613236565b925050608061373c88828901613236565b9150509295509295909350565b6000806000806080858703121561375f57600080fd5b600061376b8787613236565b945050602061377c87828801613236565b935050604061378d87828801613236565b925050606061379e87828801613236565b91505092959194509250565b6000602082840312156137bc57600080fd5b6000610bfe848461324c565b60006101a082840312156137db57600080fd5b6000610bfe8484613257565b60006101a082840312156137fa57600080fd5b6000610bfe8484613386565b600080600080610500858703121561381d57600080fd5b60006138298787613257565b9450506101a061383b87828801613236565b9350506101c061384d87828801613257565b92505061036061379e87828801613257565b60006020828403121561387157600080fd5b6000610bfe8484613241565b600080600080600060a0868803121561389557600080fd5b60006138a188886134a8565b95505060206138b288828901613241565b94505060406138c388828901613241565b93505060606138d488828901613241565b925050608061373c888289016134a8565b6000602082840312156138f757600080fd5b6000610bfe84846134b3565b600061390f8383613932565b505060200190565b600061390f8383613a39565b61392c816144be565b82525050565b61392c81614476565b600061394682614469565b613950818561446d565b935061395b83614463565b8060005b838110156139895781516139738882613903565b975061397e83614463565b92505060010161395f565b509495945050505050565b600061399f82614469565b6139a9818561446d565b93506139b483614463565b8060005b838110156139895781516139cc8882613917565b97506139d783614463565b9250506001016139b8565b60006139ed82614469565b6139f7818561446d565b9350613a0283614463565b8060005b83811015613989578151613a1a8882613917565b9750613a2583614463565b925050600101613a06565b61392c81614481565b61392c81610bc0565b61392c613a4e82610bc0565b610bc0565b6000613a5e82614469565b613a688185610607565b9350613a788185602086016144d4565b9290920192915050565b61392c81614486565b6000613a9682614469565b613aa0818561446d565b9350613ab08185602086016144d4565b613ab981614504565b9093019392505050565b6000613ad0601f8361446d565b7f4e6f2061746f6d6963206571756976616c656e7420666f7220736f7572636500815260200192915050565b6000613b0960218361446d565b7f41746f6d6963207377617073206d75737420676f207468726f756768207355538152601160fa1b602082015260400192915050565b6000613b4c60358361446d565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b6000613ba3601b8361446d565b7f4e656761746976652072617465206e6f7420737570706f727465640000000000815260200192915050565b6000613bdc60148361446d565b7306465782070726963652072657475726e656420360641b815260200192915050565b6000613c0c601b8361446d565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613c4560208361446d565b7f556e696e697469616c697a65642061746f6d696320747761702077696e646f77815260200192915050565b6000613c7e601d8361446d565b7f416d6f756e74206d7573742062652067726561746572207468616e2030000000815260200192915050565b6000613cb760328361446d565b7f41676772656761746f7220646563696d616c732073686f756c64206265206c6f815271776572206f7220657175616c20746f20323760701b602082015260400192915050565b6000613d0b60178361446d565b7f4e6f2061676772656761746f7220666f72206173736574000000000000000000815260200192915050565b6000613d44601e8361446d565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000613d7d601a8361446d565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b6000613db6601183610607565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b6000613de3602f8361446d565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b6000613e3460218361446d565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613e77601d8361446d565b7f4e6f2061746f6d6963206571756976616c656e7420666f722064657374000000815260200192915050565b6000613eb0601b8361446d565b7f6465782061676772656761746f72206164647265737320697320300000000000815260200192915050565b6000613ee9601d8361446d565b7f526573756c74206d7573742062652067726561746572207468616e2030000000815260200192915050565b6000613f22601983610607565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000613f5b601b8361446d565b7f476976656e2041676772656761746f7220697320696e76616c69640000000000815260200192915050565b6000613f9460308361446d565b7f726f756e64496473206d757374206265207468652073616d65206c656e67746881526f2061732063757272656e63794b65797360801b602082015260400192915050565b6000613fe6601c8361446d565b7f4e6f2061676772656761746f722065786973747320666f72206b657900000000815260200192915050565b61392c816144c9565b61392c816144a9565b60006140308285613a42565b6020820191506140408284613a42565b5060200192915050565b60006116748284613a53565b600061406182613da9565b915061406d8284613a42565b50602001919050565b600061406182613f15565b602081016109e78284613932565b6040810161409d8285613923565b6116746020830184613a39565b604081016140b88285613932565b6116746020830184613932565b604081016140d38285613932565b6116746020830184614012565b6040810161409d8285613932565b608081016140fc8287613932565b6141096020830186613a39565b6141166040830185613932565b612fc66060830184613a39565b60208082528101611674818461393b565b602080825281016116748184613994565b6020808252810161167481846139e2565b6040808252810161416781856139e2565b90508181036020830152610bfe81846139e2565b6040808252810161418c81856139e2565b90506116746020830184613a30565b602081016109e78284613a30565b602081016109e78284613a39565b604081016140b88285613a39565b6040810161409d8285613a39565b606081016141e18286613a39565b6141ee6020830185613a39565b610bfe6040830184613932565b604081016142098285613a39565b8181036020830152610bfe8184613a8b565b602081016109e78284613a82565b602080825281016116748184613a8b565b6020808252810161060481613ac3565b6020808252810161060481613afc565b6020808252810161060481613b3f565b6020808252810161060481613b96565b6020808252810161060481613bcf565b6020808252810161060481613bff565b6020808252810161060481613c38565b6020808252810161060481613c71565b6020808252810161060481613caa565b6020808252810161060481613cfe565b6020808252810161060481613d37565b6020808252810161060481613d70565b6020808252810161060481613dd6565b6020808252810161060481613e27565b6020808252810161060481613e6a565b6020808252810161060481613ea3565b6020808252810161060481613edc565b6020808252810161060481613f4e565b6020808252810161060481613f87565b6020808252810161060481613fd9565b604081016143888285613a39565b6116746020830184613a30565b606081016143a38286613a39565b6143b06020830185613a30565b610bfe6040830184613a30565b606081016143cb8286613a39565b6143d86020830185613a39565b610bfe6040830184613a39565b608081016143f38287613a39565b6144006020830186613a39565b6141166040830185613a39565b602081016109e7828461401b565b60405181810167ffffffffffffffff8111828210171561443a57600080fd5b604052919050565b600067ffffffffffffffff82111561445957600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b600061060482614491565b151590565b600061060482614476565b6001600160a01b031690565b6001600160d81b031690565b60ff1690565b69ffffffffffffffffffff1690565b600061060482614486565b60006106048261449d565b60005b838110156144ef5781810151838201526020016144d7565b838111156144fe576000848401525b50505050565b601f01601f191690565b61451781614476565b811461452257600080fd5b50565b61451781614481565b61451781610bc0565b61451781614486565b614517816144a9565b614517816144af56fea365627a7a72315820e33a0e59f93b59e45f9e4d74f961af789c42572a91ade91be72b0b04194912596c6578706572696d656e74616cf564736f6c63430005100040000000000000000000000000302d2451d9f47620374b54c521423bf0403916a20000000000000000000000004e3b31eb0e5cb73641ee1e65e7dcefe520ba3ef2
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102685760003560e01c8063614d08f8116101515780638da5cb5b116100c3578063c8e5bbd511610087578063c8e5bbd514610563578063ce8480ea14610584578063d89ee86114610597578063ed762450146105aa578063fce132f9146105cb578063fdadbc7e146105de57610268565b80638da5cb5b1461050d5780639eab4a3714610515578063ac82f6081461051d578063b295ad3414610530578063c2c8a6761461055057610268565b806374eded391161011557806374eded39146104b157806379ba5097146104c45780637a018a1e146104cc5780638295016a146104df5780638661cc7b146104f2578063899ffef41461050557610268565b8063614d08f814610459578063654a60ac146104615780636ce66c80146104745780637103353e1461049657806374185360146104a957610268565b80632528f0fe116101ea57806338aa1b99116101ae57806338aa1b99146103e25780633f0e084f146103f55780634308a94f146104085780634c36b837146104295780634f72def61461043e57806353a47bb71461045157610268565b80632528f0fe146103815780632678df961461039457806326bd30fa146103b45780632af64bd3146103c75780632bed9e0c146103cf57610268565b80630a7d36d1116102315780630a7d36d1146103105780630c71cd23146103235780630ee4951b14610344578063109e46a2146103595780631627540c1461036c57610268565b80629919c01461026d578063045056f81461029657806304f3bcec146102b8578063055286e0146102cd57806305a046e5146102f0575b600080fd5b61028061027b3660046135ff565b6105f1565b60405161028d919061419b565b60405180910390f35b6102a96102a43660046135ff565b61060c565b60405161028d93929190614395565b6102c061077f565b60405161028d919061421b565b6102e06102db366004613687565b61078e565b60405161028d94939291906143e5565b6103036102fe36600461352f565b61096b565b60405161028d9190614145565b61028061031e36600461352f565b6109ed565b6103366103313660046135ff565b610b16565b60405161028d92919061437a565b61034c610bb3565b60405161028d91906141a9565b61034c610367366004613749565b610bc3565b61037f61037a3660046134be565b610c06565b005b61028061038f3660046135ff565b610c64565b6103a76103a23660046134be565b610c70565b60405161028d9190614134565b6102e06103c2366004613806565b610d24565b610280610de3565b61037f6103dd3660046135ff565b610efa565b6102806103f03660046135ff565b610fb7565b61037f61040336600461361d565b610fc5565b61041b6104163660046135ff565b6111cc565b60405161028d9291906141c5565b610431611204565b60405161028d9190614081565b61034c61044c3660046135ff565b61120e565b61043161122c565b61034c61123b565b61034c61046f366004613687565b61125f565b6104876104823660046136d4565b611277565b60405161028d939291906143bd565b6102c06104a43660046135ff565b6112dc565b61037f6112f7565b61037f6104bf3660046137aa565b61144d565b61037f611512565b61034c6104da3660046135ff565b6115ae565b6104876104ed366004613687565b6115b9565b6102806105003660046135ff565b6115d9565b6103a761167b565b6104316116f2565b6102c0611701565b61034c61052b3660046135ff565b6117ad565b61054361053e3660046135ff565b6117c8565b60405161028d919061440d565b61030361055e36600461352f565b6117dd565b61057661057136600461352f565b611855565b60405161028d92919061417b565b61034c6105923660046135ff565b6119a5565b6102806105a5366004613571565b6119b0565b6105bd6105b8366004613687565b611af5565b60405161028d929190614156565b6102806105d93660046137c8565b611bd3565b61041b6105ec366004613657565b611cb6565b6000610604826105ff611ccf565b611d79565b90505b919050565b600081815260046020526040812054819081906001600160a01b0316631cd554d160e21b85148061064557506001600160a01b03811615155b61066a5760405162461bcd60e51b8152600401610661906142ca565b60405180910390fd5b610672613083565b61067b86611da4565b9050631cd554d160e21b8614156106a657516001600160d81b03169350600092508291506107789050565b80516001600160d81b031694506106bb611f6e565b815160405163413caeb560e01b81526001600160a01b03929092169163413caeb5916106ec918691906004016140c5565b602060405180830381600087803b15801561070657600080fd5b505af115801561071a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061073e91908101906135e1565b935061075c61074b611ccf565b826020015164ffffffffff16611f8a565b8061077357506107738661076e611fa5565b612006565b925050505b9193909250565b6002546001600160a01b031681565b60008060008061079c61309a565b6107a46120d6565b6001600160a01b031663697b659b338a6040518363ffffffff1660e01b81526004016107d192919061408f565b6101a06040518083038186803b1580156107ea57600080fd5b505afa1580156107fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061082291908101906137e7565b905061082c61309a565b6108346120d6565b6001600160a01b031663697b659b33896040518363ffffffff1660e01b815260040161086192919061408f565b6101a06040518083038186803b15801561087a57600080fd5b505afa15801561088e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b291908101906137e7565b90506108bc61309a565b6108c46120d6565b6001600160a01b031663697b659b33631cd554d160e21b6040518363ffffffff1660e01b81526004016108f892919061408f565b6101a06040518083038186803b15801561091157600080fd5b505afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061094991908101906137e7565b9050610957838a8484610d24565b965096509650965050505093509350935093565b6060808383905060405190808252806020026020018201604052801561099b578160200160208202803883390190505b50905060005b838110156109e3576109c48585838181106109b857fe5b905060200201356120fc565b8282815181106109d057fe5b60209081029190910101526001016109a1565b5090505b92915050565b6000806109f8611ccf565b90506060610a3885858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061211892505050565b905060005b84811015610b0a57631cd554d160e21b868683818110610a5957fe5b905060200201351415610a6b57610b02565b610a73613083565b610a8e878784818110610a8257fe5b90506020020135611da4565b9050828281518110610a9c57fe5b602002602001015180610abf5750610abf84826020015164ffffffffff16611f8a565b80610aee5750610aee878784818110610ad457fe5b9050602002013582600001516001600160d81b0316612293565b15610b005760019450505050506109e7565b505b600101610a3d565b50600095945050505050565b600080610b21613083565b610b2a84611da4565b9050631cd554d160e21b841415610b5057516001600160d81b0316915060009050610bae565b8051610b6e610b5d611ccf565b836020015164ffffffffff16611f8a565b80610b805750610b808561076e611fa5565b80610b9d5750610b9d8583600001516001600160d81b0316612293565b6001600160d81b0390911693509150505b915091565b6000610bbd611ccf565b90505b90565b600083815b610bd5878360010161232d565b915050801580610be6575083850181115b15610bf357509050610bfe565b600190910190610bc8565b949350505050565b610c0e6124cf565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290610c59908390614081565b60405180910390a150565b600080610bfe83610b16565b600654604080518281526020808402820101909152606091600091908015610ca2578160200160208202803883390190505b50915060005b600654811015610d1d57600060068281548110610cc157fe5b600091825260208083209091015480835260049091526040909120549091506001600160a01b039081169086161415610d145780848480600101955081518110610d0757fe5b6020026020010181815250505b50600101610ca8565b5050919050565b600080600080610d3d88600001518888600001516124fb565b8a519295509093509150600090610d539061254d565b90506000610d64886000015161254d565b90506000808315610d7757859150610d8e565b610d8b86610d868e8c8f61262d565b612841565b91505b8215610d9b575083610db2565b610daf85610daa8b8d8f61262d565b612857565b90505b610dd281610dc68d8563ffffffff61286616565b9063ffffffff6128a016565b975050505050945094509450949050565b60006060610def61167b565b905060005b8151811015610ef1576000828281518110610e0b57fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a72190610e5c9085906004016141a9565b60206040518083038186803b158015610e7457600080fd5b505afa158015610e88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610eac91908101906134dc565b6001600160a01b0316141580610ed757506000818152600360205260409020546001600160a01b0316155b15610ee85760009350505050610bc0565b50600101610df4565b50600191505090565b610f026124cf565b6000818152600460205260409020546001600160a01b031680610f375760405162461bcd60e51b81526004016106619061436a565b600082815260046020908152604080832080546001600160a01b031916905560059091528120805460ff19169055610f708360066128d5565b90508015610fb2577fec70e890fc7db7de4059b114c9093a1f41283d18ffcfbcac45566feea4d4f7778383604051610fa99291906141b7565b60405180910390a15b505050565b60006106048261076e611fa5565b610fcd6124cf565b60008190506000816001600160a01b031663668a0f026040518163ffffffff1660e01b815260040160206040518083038186803b15801561100d57600080fd5b505afa158015611021573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611045919081019061385f565b10156110635760405162461bcd60e51b81526004016106619061434a565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561109e57600080fd5b505afa1580156110b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110d691908101906138e5565b9050601b8160ff1611156110fc5760405162461bcd60e51b8152600401610661906142ba565b6000848152600460205260409020546001600160a01b031661114e57600680546001810182556000919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f018490555b600084815260046020908152604080832080546001600160a01b0319166001600160a01b038716179055600590915290819020805460ff191660ff8416179055517f0bcae573430f69c5361e5d76534d3f61d2d803958778680cd74be9dc6299bc63906111be90869085906141b7565b60405180910390a150505050565b6000806111d7613083565b6111e084611da4565b80516020909101516001600160d81b03909116935064ffffffffff16915050915091565b6000610bbd611fa5565b6006818154811061121b57fe5b600091825260209091200154905081565b6001546001600160a01b031681565b7f45786368616e676552617465735769746844657850726963696e67000000000081565b600061126c8484846124fb565b509095945050505050565b6000806000611286888661232d565b5091508786141561129b5750859150806112d1565b6112a5868561232d565b50905080156112d1576112ce816112c2898563ffffffff61297916565b9063ffffffff61298e16565b92505b955095509592505050565b6004602052600090815260409020546001600160a01b031681565b606061130161167b565b905060005b815181101561144957600082828151811061131d57fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d01838460405160200161135f9190614076565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161138b9291906141fb565b60206040518083038186803b1580156113a357600080fd5b505afa1580156113b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113db91908101906134dc565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa689061143790849084906141b7565b60405180910390a15050600101611306565b5050565b6114556124cf565b61145d6129a3565b6001600160a01b0316634dca09786c45786368616e6765526174657360981b713232bc283934b1b2a0b3b3b932b3b0ba37b960711b846040518463ffffffff1660e01b81526004016114b1939291906141d3565b600060405180830381600087803b1580156114cb57600080fd5b505af11580156114df573d6000803e3d6000fd5b505050507f8a51d16f378c74938a4b9290afe425bbfba62f05aa9d27bff5e892f62696f76081604051610c599190614081565b6001546001600160a01b0316331461153c5760405162461bcd60e51b81526004016106619061425a565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9261157f926001600160a01b03918216929116906140aa565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000610604826129c0565b60008060006115c98686866124fb565b9250925092505b93509350939050565b60006115e361309a565b6115eb6120d6565b6001600160a01b031663697b659b33856040518363ffffffff1660e01b815260040161161892919061408f565b6101a06040518083038186803b15801561163157600080fd5b505afa158015611645573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061166991908101906137e7565b905061167481611bd3565b9392505050565b606080611686612a70565b6040805160018082528183019092529192506060919060208083019080388339019050509050772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b816000815181106116d557fe5b6020026020010181815250506116eb8282612ac0565b9250505090565b6000546001600160a01b031681565b600061170b6129a3565b6001600160a01b0316639ee5955a6c45786368616e6765526174657360981b713232bc283934b1b2a0b3b3b932b3b0ba37b960711b6040518363ffffffff1660e01b815260040161175d9291906141c5565b60206040518083038186803b15801561177557600080fd5b505afa158015611789573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bbd91908101906134dc565b60006117b882611da4565b516001600160d81b031692915050565b60056020526000908152604090205460ff1681565b6060808383905060405190808252806020026020018201604052801561180d578160200160208202803883390190505b50905060005b838110156109e35761183685858381811061182a57fe5b905060200201356117ad565b82828151811061184257fe5b6020908102919091010152600101611813565b6060600083839050604051908082528060200260200182016040528015611886578160200160208202803883390190505b5091506000611893611ccf565b905060606118d386868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061211892505050565b905060005b8581101561199b576118e8613083565b6118f7888884818110610a8257fe5b905080600001516001600160d81b031686838151811061191357fe5b602002602001018181525050841580156119465750631cd554d160e21b88888481811061193c57fe5b9050602002013514155b156119925782828151811061195757fe5b60200260200101518061197a575061197a84826020015164ffffffffff16611f8a565b8061198f575061198f888884818110610ad457fe5b94505b506001016118d8565b5050509250929050565b6000610604826120fc565b60008184146119d15760405162461bcd60e51b81526004016106619061435a565b60006119db611ccf565b90506060611a1b87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061211892505050565b905060005b86811015611ae757631cd554d160e21b888883818110611a3c57fe5b905060200201351415611a4e57611adf565b600080611a7f8a8a85818110611a6057fe5b90506020020135898986818110611a7357fe5b9050602002013561232d565b91509150838381518110611a8f57fe5b602002602001015180611aa75750611aa78582611f8a565b80611ac95750611ac98a8a85818110611abc57fe5b9050602002013583612293565b15611adc57600195505050505050610bfe565b50505b600101611a20565b506000979650505050505050565b60608083604051908082528060200260200182016040528015611b22578160200160208202803883390190505b50915083604051908082528060200260200182016040528015611b4f578160200160208202803883390190505b50905060008311611b6857611b63856129c0565b611b6a565b825b925060005b84811015611bc957611b81868561232d565b848381518110611b8d57fe5b60200260200101848481518110611ba057fe5b60209081029190910101919091525283611bba5750611bcb565b60001990930192600101611b6f565b505b935093915050565b8051600090631cd554d160e21b1415611bee57506000610607565b60c082015160e0830151811580611c03575080155b15611c1357600092505050610607565b6000611c25428463ffffffff612b7c16565b90506000611c3686600001516129c0565b90505b8215611caa57600080611c5088600001518461232d565b9150915080600014158015611c6457508381105b15611c785760009650505050505050610607565b811580611c83575080155b15611c8f575050611caa565b82611c9b575050611caa565b50506000199283019201611c39565b50600195945050505050565b600080611cc3848461232d565b915091505b9250929050565b6000611cd96129a3565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6e1c985d1954dd185b1954195c9a5bd9608a1b6040518363ffffffff1660e01b8152600401611d299291906141c5565b60206040518083038186803b158015611d4157600080fd5b505afa158015611d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bbd919081019061385f565b6000631cd554d160e21b831415611d92575060006109e7565b61167482611d9f856120fc565b611f8a565b611dac613083565b631cd554d160e21b821415611e5c5760405180604001604052807384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611e0a57600080fd5b505af4158015611e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e42919081019061385f565b6001600160d81b0316815260006020909101529050610607565b6000828152600460205260409020546001600160a01b03168015611f685760408051600481526024810182526020810180516001600160e01b0316633fabe5a360e21b17905290516000906060906001600160a01b03851690611ec090859061404a565b600060405180830381855afa9150503d8060008114611efb576040519150601f19603f3d011682016040523d82523d6000602084013e611f00565b606091505b50915091508115611f645760008082806020019051611f22919081019061387d565b509350509250506040518060400160405280611f3e8a85612ba4565b6001600160d81b031681526020018264ffffffffff168152509650505050505050610607565b5050505b50919050565b6000610bbd6d21b4b931bab4ba213932b0b5b2b960911b612c44565b600042611f9d838563ffffffff612ca116565b109392505050565b6000611faf6129a3565b6001600160a01b0316639ee5955a6d53797374656d53657474696e677360901b7561676772656761746f725761726e696e67466c61677360501b6040518363ffffffff1660e01b815260040161175d9291906141c5565b6000631cd554d160e21b83141561201f575060006109e7565b6000838152600460205260409020546001600160a01b031680158061204b57506001600160a01b038316155b1561205a5760009150506109e7565b604051631abf23ff60e11b81526001600160a01b0384169063357e47fe90612086908490600401614081565b60206040518083038186803b15801561209e57600080fd5b505afa1580156120b2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bfe91908101906135e1565b6000610bbd772234b932b1ba24b73a32b3b930ba34b7b726b0b730b3b2b960411b612c44565b600061210782611da4565b6020015164ffffffffff1692915050565b60606000612124611fa5565b90506001600160a01b038116156122605760608351604051908082528060200260200182016040528015612162578160200160208202803883390190505b50905060005b84518110156121d7576004600086838151811061218157fe5b6020026020010151815260200190815260200160002060009054906101000a90046001600160a01b03168282815181106121b757fe5b6001600160a01b0390921660209283029190910190910152600101612168565b50604051631f5c8f2b60e21b81526001600160a01b03831690637d723cac90612204908490600401614123565b60006040518083038186803b15801561221c57600080fd5b505afa158015612230573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261225891908101906134fa565b925050611f68565b825160405190808252806020026020018201604052801561228b578160200160208202803883390190505b509392505050565b600061229d611f6e565b6000848152600460208190526040918290205491516318b844ad60e01b81526001600160a01b03938416936318b844ad936122dd939116918791016140e0565b60206040518083038186803b1580156122f557600080fd5b505afa158015612309573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061167491908101906135e1565b600080631cd554d160e21b8414156123c6577384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561238357600080fd5b505af4158015612397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123bb919081019061385f565b915060009050611cc8565b6000848152600460205260409020546001600160a01b031680156124c7576060846040516024016123f791906141a9565b60408051601f198184030181529181526020820180516001600160e01b0316639a6fc8f560e01b179052519091506000906060906001600160a01b0385169061244190859061404a565b600060405180830381855afa9150503d806000811461247c576040519150601f19603f3d011682016040523d82523d6000602084013e612481565b606091505b509150915081156124c357600080828060200190516124a3919081019061387d565b509350509250506124b48a83612ba4565b97509550611cc8945050505050565b5050505b509250929050565b6000546001600160a01b031633146124f95760405162461bcd60e51b8152600401610661906142fa565b565b6000806000612509866117ad565b91508386141561251d5750839150806115d0565b612526846117ad565b905080156115d057612542816112c2878563ffffffff61297916565b925093509350939050565b60006125576129a3565b6001600160a01b031663d994502d6d53797374656d53657474696e677360901b7f70757265436861696e6c696e6b466f7241746f6d696373456e61626c65640000856040516020016125aa929190614024565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b81526004016125dd9291906141c5565b60206040518083038186803b1580156125f557600080fd5b505afa158015612609573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060491908101906135e1565b60008161264c5760405162461bcd60e51b8152600401610661906142aa565b8351631cd554d160e21b148061266957508251631cd554d160e21b145b6126855760405162461bcd60e51b81526004016106619061424a565b60408401516001600160a01b0381166126b05760405162461bcd60e51b81526004016106619061423a565b60408401516001600160a01b0381166126db5760405162461bcd60e51b81526004016106619061431a565b600061278185610dc67384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b15801561272857600080fd5b505af415801561273c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612760919081019061385f565b6127758b6020015188888c8f60800151612cc6565b9063ffffffff61286616565b9050806127a05760405162461bcd60e51b81526004016106619061433a565b8551631cd554d160e21b146128345761282f817384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b1580156127f757600080fd5b505af415801561280b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112c2919081019061385f565b612836565b805b979650505050505050565b60008183106128505781611674565b5090919050565b60008183116128505781611674565b600082612875575060006109e7565b8282028284828161288257fe5b04146116745760405162461bcd60e51b81526004016106619061430a565b60008082116128c15760405162461bcd60e51b8152600401610661906142ea565b60008284816128cc57fe5b04949350505050565b6000805b825481101561296f57838382815481106128ef57fe5b906000526020600020015414156129675782818154811061290c57fe5b600091825260208220015582548390600019810190811061292957fe5b906000526020600020015483828154811061294057fe5b600091825260209091200155825461295c846000198301613117565b5060019150506109e7565b6001016128d9565b5060009392505050565b60006116748383670de0b6b3a7640000612fcf565b60006116748383670de0b6b3a764000061300c565b6000610bbd6e466c657869626c6553746f7261676560881b612c44565b6000631cd554d160e21b8214156129d957506000610607565b6000828152600460205260409020546001600160a01b03168015611f6857806001600160a01b031663668a0f026040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3057600080fd5b505afa158015612a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a68919081019061385f565b915050610607565b606080612a7b613032565b60408051600180825281830190925291925060609190602080830190803883390190505090506d21b4b931bab4ba213932b0b5b2b960911b816000815181106116d557fe5b60608151835101604051908082528060200260200182016040528015612af0578160200160208202803883390190505b50905060005b8351811015612b3257838181518110612b0b57fe5b6020026020010151828281518110612b1f57fe5b6020908102919091010152600101612af6565b5060005b8251811015612b7557828181518110612b4b57fe5b6020026020010151828286510181518110612b6257fe5b6020908102919091010152600101612b36565b5092915050565b600082821115612b9e5760405162461bcd60e51b8152600401610661906142da565b50900390565b600080821215612bc65760405162461bcd60e51b81526004016106619061426a565b60008381526005602052604090205460ff1682811580612be65750816012145b15612bf057610bfe565b6012821015612c19576012829003600a0a612c11828263ffffffff61286616565b915050610bfe565b6012821115610bfe576011198201600a0a612c3a828263ffffffff6128a016565b9695505050505050565b60008181526003602090815260408083205490516001600160a01b039091169182151591612c7491869101614056565b60405160208183030381529060405290612b755760405162461bcd60e51b81526004016106619190614229565b6000828201838110156116745760405162461bcd60e51b81526004016106619061428a565b600080612dcf7384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612d1057600080fd5b505af4158015612d24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d48919081019061385f565b610dc6886001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8457600080fd5b505afa158015612d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612dbc91908101906138e5565b879060ff16600a0a63ffffffff61286616565b90506001600160a01b038716612df75760405162461bcd60e51b81526004016106619061432a565b82612e145760405162461bcd60e51b81526004016106619061429a565b604051637c66194960e01b81526000906001600160a01b03891690637c66194990612e49908a9086908b908a906004016140ee565b60206040518083038186803b158015612e6157600080fd5b505afa158015612e75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e99919081019061385f565b905060008111612ebb5760405162461bcd60e51b81526004016106619061427a565b612fc1866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612ef757600080fd5b505afa158015612f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f2f91908101906138e5565b60ff16600a0a610dc67384d626b2bb4d0f064067e4bf80fce7055d8f3e7b63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7c57600080fd5b505af4158015612f90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612fb4919081019061385f565b849063ffffffff61286616565b925050505b95945050505050565b600080600a8304612fe6868663ffffffff61286616565b81612fed57fe5b0490506005600a825b061061300057600a015b600a9004949350505050565b60008061302684610dc687600a870263ffffffff61286616565b90506005600a82612ff6565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b8160008151811061307457fe5b60200260200101818152505090565b604080518082019091526000808252602082015290565b604051806101a001604052806000801916815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815481835581811115610fb257600083815260209020610fb2918101908301610bc091905b80821115613150576000815560010161313c565b5090565b80356109e78161450e565b80516109e78161450e565b600082601f83011261317b57600080fd5b815161318e61318982614442565b61441b565b915081818352602084019350602081019050838560208402820111156131b357600080fd5b60005b838110156131df57816131c9888261322b565b84525060209283019291909101906001016131b6565b5050505092915050565b60008083601f8401126131fb57600080fd5b50813567ffffffffffffffff81111561321357600080fd5b602083019150836020820283011115611cc857600080fd5b80516109e781614525565b80356109e78161452e565b80516109e78161452e565b80356109e781614537565b60006101a0828403121561326a57600080fd5b6132756101a061441b565b905060006132838484613236565b825250602061329484848301613154565b60208301525060406132a884828501613154565b60408301525060606132bc84828501613236565b60608301525060806132d084828501613236565b60808301525060a06132e484828501613236565b60a08301525060c06132f884828501613236565b60c08301525060e061330c84828501613236565b60e08301525061010061332184828501613236565b6101008301525061012061333784828501613236565b6101208301525061014061334d84828501613236565b6101408301525061016061336384828501613236565b6101608301525061018061337984828501613236565b6101808301525092915050565b60006101a0828403121561339957600080fd5b6133a46101a061441b565b905060006133b28484613241565b82525060206133c38484830161315f565b60208301525060406133d78482850161315f565b60408301525060606133eb84828501613241565b60608301525060806133ff84828501613241565b60808301525060a061341384828501613241565b60a08301525060c061342784828501613241565b60c08301525060e061343b84828501613241565b60e08301525061010061345084828501613241565b6101008301525061012061346684828501613241565b6101208301525061014061347c84828501613241565b6101408301525061016061349284828501613241565b6101608301525061018061337984828501613241565b80516109e781614549565b80516109e781614540565b6000602082840312156134d057600080fd5b6000610bfe8484613154565b6000602082840312156134ee57600080fd5b6000610bfe848461315f565b60006020828403121561350c57600080fd5b815167ffffffffffffffff81111561352357600080fd5b610bfe8482850161316a565b6000806020838503121561354257600080fd5b823567ffffffffffffffff81111561355957600080fd5b613565858286016131e9565b92509250509250929050565b6000806000806040858703121561358757600080fd5b843567ffffffffffffffff81111561359e57600080fd5b6135aa878288016131e9565b9450945050602085013567ffffffffffffffff8111156135c957600080fd5b6135d5878288016131e9565b95989497509550505050565b6000602082840312156135f357600080fd5b6000610bfe848461322b565b60006020828403121561361157600080fd5b6000610bfe8484613236565b6000806040838503121561363057600080fd5b600061363c8585613236565b925050602061364d85828601613154565b9150509250929050565b6000806040838503121561366a57600080fd5b60006136768585613236565b925050602061364d85828601613236565b60008060006060848603121561369c57600080fd5b60006136a88686613236565b93505060206136b986828701613236565b92505060406136ca86828701613236565b9150509250925092565b600080600080600060a086880312156136ec57600080fd5b60006136f88888613236565b955050602061370988828901613236565b945050604061371a88828901613236565b935050606061372b88828901613236565b925050608061373c88828901613236565b9150509295509295909350565b6000806000806080858703121561375f57600080fd5b600061376b8787613236565b945050602061377c87828801613236565b935050604061378d87828801613236565b925050606061379e87828801613236565b91505092959194509250565b6000602082840312156137bc57600080fd5b6000610bfe848461324c565b60006101a082840312156137db57600080fd5b6000610bfe8484613257565b60006101a082840312156137fa57600080fd5b6000610bfe8484613386565b600080600080610500858703121561381d57600080fd5b60006138298787613257565b9450506101a061383b87828801613236565b9350506101c061384d87828801613257565b92505061036061379e87828801613257565b60006020828403121561387157600080fd5b6000610bfe8484613241565b600080600080600060a0868803121561389557600080fd5b60006138a188886134a8565b95505060206138b288828901613241565b94505060406138c388828901613241565b93505060606138d488828901613241565b925050608061373c888289016134a8565b6000602082840312156138f757600080fd5b6000610bfe84846134b3565b600061390f8383613932565b505060200190565b600061390f8383613a39565b61392c816144be565b82525050565b61392c81614476565b600061394682614469565b613950818561446d565b935061395b83614463565b8060005b838110156139895781516139738882613903565b975061397e83614463565b92505060010161395f565b509495945050505050565b600061399f82614469565b6139a9818561446d565b93506139b483614463565b8060005b838110156139895781516139cc8882613917565b97506139d783614463565b9250506001016139b8565b60006139ed82614469565b6139f7818561446d565b9350613a0283614463565b8060005b83811015613989578151613a1a8882613917565b9750613a2583614463565b925050600101613a06565b61392c81614481565b61392c81610bc0565b61392c613a4e82610bc0565b610bc0565b6000613a5e82614469565b613a688185610607565b9350613a788185602086016144d4565b9290920192915050565b61392c81614486565b6000613a9682614469565b613aa0818561446d565b9350613ab08185602086016144d4565b613ab981614504565b9093019392505050565b6000613ad0601f8361446d565b7f4e6f2061746f6d6963206571756976616c656e7420666f7220736f7572636500815260200192915050565b6000613b0960218361446d565b7f41746f6d6963207377617073206d75737420676f207468726f756768207355538152601160fa1b602082015260400192915050565b6000613b4c60358361446d565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b6000613ba3601b8361446d565b7f4e656761746976652072617465206e6f7420737570706f727465640000000000815260200192915050565b6000613bdc60148361446d565b7306465782070726963652072657475726e656420360641b815260200192915050565b6000613c0c601b8361446d565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613c4560208361446d565b7f556e696e697469616c697a65642061746f6d696320747761702077696e646f77815260200192915050565b6000613c7e601d8361446d565b7f416d6f756e74206d7573742062652067726561746572207468616e2030000000815260200192915050565b6000613cb760328361446d565b7f41676772656761746f7220646563696d616c732073686f756c64206265206c6f815271776572206f7220657175616c20746f20323760701b602082015260400192915050565b6000613d0b60178361446d565b7f4e6f2061676772656761746f7220666f72206173736574000000000000000000815260200192915050565b6000613d44601e8361446d565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b6000613d7d601a8361446d565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b6000613db6601183610607565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b6000613de3602f8361446d565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b6000613e3460218361446d565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613e77601d8361446d565b7f4e6f2061746f6d6963206571756976616c656e7420666f722064657374000000815260200192915050565b6000613eb0601b8361446d565b7f6465782061676772656761746f72206164647265737320697320300000000000815260200192915050565b6000613ee9601d8361446d565b7f526573756c74206d7573742062652067726561746572207468616e2030000000815260200192915050565b6000613f22601983610607565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000613f5b601b8361446d565b7f476976656e2041676772656761746f7220697320696e76616c69640000000000815260200192915050565b6000613f9460308361446d565b7f726f756e64496473206d757374206265207468652073616d65206c656e67746881526f2061732063757272656e63794b65797360801b602082015260400192915050565b6000613fe6601c8361446d565b7f4e6f2061676772656761746f722065786973747320666f72206b657900000000815260200192915050565b61392c816144c9565b61392c816144a9565b60006140308285613a42565b6020820191506140408284613a42565b5060200192915050565b60006116748284613a53565b600061406182613da9565b915061406d8284613a42565b50602001919050565b600061406182613f15565b602081016109e78284613932565b6040810161409d8285613923565b6116746020830184613a39565b604081016140b88285613932565b6116746020830184613932565b604081016140d38285613932565b6116746020830184614012565b6040810161409d8285613932565b608081016140fc8287613932565b6141096020830186613a39565b6141166040830185613932565b612fc66060830184613a39565b60208082528101611674818461393b565b602080825281016116748184613994565b6020808252810161167481846139e2565b6040808252810161416781856139e2565b90508181036020830152610bfe81846139e2565b6040808252810161418c81856139e2565b90506116746020830184613a30565b602081016109e78284613a30565b602081016109e78284613a39565b604081016140b88285613a39565b6040810161409d8285613a39565b606081016141e18286613a39565b6141ee6020830185613a39565b610bfe6040830184613932565b604081016142098285613a39565b8181036020830152610bfe8184613a8b565b602081016109e78284613a82565b602080825281016116748184613a8b565b6020808252810161060481613ac3565b6020808252810161060481613afc565b6020808252810161060481613b3f565b6020808252810161060481613b96565b6020808252810161060481613bcf565b6020808252810161060481613bff565b6020808252810161060481613c38565b6020808252810161060481613c71565b6020808252810161060481613caa565b6020808252810161060481613cfe565b6020808252810161060481613d37565b6020808252810161060481613d70565b6020808252810161060481613dd6565b6020808252810161060481613e27565b6020808252810161060481613e6a565b6020808252810161060481613ea3565b6020808252810161060481613edc565b6020808252810161060481613f4e565b6020808252810161060481613f87565b6020808252810161060481613fd9565b604081016143888285613a39565b6116746020830184613a30565b606081016143a38286613a39565b6143b06020830185613a30565b610bfe6040830184613a30565b606081016143cb8286613a39565b6143d86020830185613a39565b610bfe6040830184613a39565b608081016143f38287613a39565b6144006020830186613a39565b6141166040830185613a39565b602081016109e7828461401b565b60405181810167ffffffffffffffff8111828210171561443a57600080fd5b604052919050565b600067ffffffffffffffff82111561445957600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b600061060482614491565b151590565b600061060482614476565b6001600160a01b031690565b6001600160d81b031690565b60ff1690565b69ffffffffffffffffffff1690565b600061060482614486565b60006106048261449d565b60005b838110156144ef5781810151838201526020016144d7565b838111156144fe576000848401525b50505050565b601f01601f191690565b61451781614476565b811461452257600080fd5b50565b61451781614481565b61451781610bc0565b61451781614486565b614517816144a9565b614517816144af56fea365627a7a72315820e33a0e59f93b59e45f9e4d74f961af789c42572a91ade91be72b0b04194912596c6578706572696d656e74616cf564736f6c63430005100040
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
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ 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.