Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
6674007 | 1 hr ago | 0.00033441 ETH | ||||
6674007 | 1 hr ago | 0.00033441 ETH | ||||
6673993 | 1 hr ago | 0.00033441 ETH | ||||
6673918 | 1 hr ago | 0.00033441 ETH | ||||
6673918 | 1 hr ago | 0.00033441 ETH | ||||
6673894 | 1 hr ago | 0.00033441 ETH | ||||
6673894 | 1 hr ago | 0.00033441 ETH | ||||
6673848 | 1 hr ago | 0.00033441 ETH | ||||
6673848 | 1 hr ago | 0.00033441 ETH | ||||
6673840 | 1 hr ago | 0.00033441 ETH | ||||
6673840 | 1 hr ago | 0.00033441 ETH | ||||
6673787 | 1 hr ago | 0.00033441 ETH | ||||
6673787 | 1 hr ago | 0.00033441 ETH | ||||
6673775 | 2 hrs ago | 0.00033441 ETH | ||||
6673775 | 2 hrs ago | 0.00033441 ETH | ||||
6673729 | 2 hrs ago | 0.00033441 ETH | ||||
6673729 | 2 hrs ago | 0.00033441 ETH | ||||
6673721 | 2 hrs ago | 0.00033441 ETH | ||||
6673721 | 2 hrs ago | 0.00033441 ETH | ||||
6673718 | 2 hrs ago | 0.00033441 ETH | ||||
6673718 | 2 hrs ago | 0.00033441 ETH | ||||
6673707 | 2 hrs ago | 0.00033441 ETH | ||||
6673707 | 2 hrs ago | 0.00033441 ETH | ||||
6673689 | 2 hrs ago | 0.00033441 ETH | ||||
6673689 | 2 hrs ago | 0.00033441 ETH |
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:
ExchangerWithFeeRecAlternativesLightChain
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Inheritance import "./Exchanger.sol"; // Internal references // import "./MinimalProxyFactory.sol"; import "../interfaces/IAddressResolver.sol"; import "../interfaces/IERC20.sol"; import "../interfaces/IExchanger.sol"; contract ExchangerWithFeeRecAlternativesLightChain is Exchanger { // bytes32 public constant override CONTRACT_NAME = "ExchangerWithFeeRecAlternatives"; using SafeMath for uint256; struct ExchangeVolumeAtPeriod { uint64 time; uint192 volume; } ExchangeVolumeAtPeriod public lastAtomicVolume; uint16 internal constant PT_EXCHANGE = 5; constructor( address _owner, address _resolver ) // MinimalProxyFactory() Exchanger(_owner, _resolver) {} /* ========== VIEWS ========== */ function getAmountsForAtomicExchange( uint256 sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns (uint256 amountReceived, uint256 fee, uint256 exchangeFeeRate) { (amountReceived, fee, exchangeFeeRate, , , ) = _getAmountsForAtomicExchangeMinusFees( sourceAmount, sourceCurrencyKey, destinationCurrencyKey ); } function getSendExchangeGasFee( address _account, bytes32 _sourceKey, uint256 _sourceAmount, bytes32 _destKey, bytes32 _bridgeName, uint16 _destChainId ) external view returns (uint256) { uint256 amountReceived; uint256 fee; (amountReceived, fee, , , , ) = _getAmountsForAtomicExchangeMinusFees(_sourceAmount, _sourceKey, _destKey); bytes memory lzPayload = abi.encode( PT_EXCHANGE, abi.encodePacked(_account), _sourceKey, _sourceAmount, _destKey, amountReceived, fee, _destChainId ); return synthrBridge(_bridgeName).calcFee(lzPayload, PT_EXCHANGE, _destChainId); } /* ========== MUTATIVE FUNCTIONS ========== */ function exchangeAtomically( uint256 minAmount, IExchanger.ExchangeArgs calldata args, bytes32 bridgeName ) external payable onlyWrappedSynthrorSynth returns (uint256 amountReceived) { (amountReceived, ) = _exchangeAtomically(args, bridgeName); require(amountReceived >= minAmount, "The amount received is below the minimum amount specified."); } function _exchangeAtomically( IExchanger.ExchangeArgs memory _args, bytes32 bridgeName ) internal returns (uint256 amountReceived, uint256 fee) { IExchanger.ExchangeArgs memory args = _args; _ensureCanExchange(args.sourceCurrencyKey, args.sourceAmount, args.destCurrencyKey); require(!exchangeRates().synthTooVolatileForAtomicExchange(args.sourceCurrencyKey), "Src synth value is volatile."); require(!exchangeRates().synthTooVolatileForAtomicExchange(args.destCurrencyKey), "Dest synth value is volatile."); (args.sourceAmount, args.reclaimed, args.refunded) = _settleAndCalcSourceAmountRemaining( args.sourceAmount, args.fromAccount, args.sourceCurrencyKey ); // If, after settlement the user has no balance left (highly unlikely), then return to prevent // emitting events of 0 and don't revert so as to ensure the settlement queue is emptied if (args.sourceAmount == 0) { return (0, 0); } uint256 exchangeFeeRate; uint256 systemConvertedAmount; uint256 systemSourceRate; uint256 systemDestinationRate; // Note: also ensures the given synths are allowed to be atomically exchanged ( amountReceived, // output amount with fee taken out (denominated in dest currency) fee, // fee amount (denominated in dest currency) exchangeFeeRate, // applied fee rate systemConvertedAmount, // current system value without fees (denominated in dest currency) systemSourceRate, // current system rate for src currency systemDestinationRate // current system rate for dest currency ) = _getAmountsForAtomicExchangeMinusFees(args.sourceAmount, args.sourceCurrencyKey, args.destCurrencyKey); args.destAmount = amountReceived; args.fee = fee; // SIP-65: Decentralized Circuit Breaker (checking current system rates) if (_exchangeRatesCircuitBroken(args.sourceCurrencyKey, args.destCurrencyKey)) { return (0, 0); } // Sanity check atomic output's value against current system value (checking atomic rates) require( !exchangeCircuitBreaker().isDeviationAboveThreshold(systemConvertedAmount, amountReceived.add(fee)), "Atomic rate deviates too much" ); // Determine sUSD value of exchange uint256 sourceSusdValue; if (args.sourceCurrencyKey == sUSD) { // Use after-settled amount as this is amount converted (not sourceAmount) sourceSusdValue = _args.sourceAmount; } else if (args.destCurrencyKey == sUSD) { // In this case the systemConvertedAmount would be the fee-free sUSD value of the source synth sourceSusdValue = systemConvertedAmount; } else { // Otherwise, convert source to sUSD value (uint256 amountReceivedInUSD, uint256 sUsdFee, , , , ) = _getAmountsForAtomicExchangeMinusFees( _args.sourceAmount, args.sourceCurrencyKey, sUSD ); sourceSusdValue = amountReceivedInUSD.add(sUsdFee); } // Check and update atomic volume limit _checkAndUpdateAtomicVolume(sourceSusdValue); // Note: We don't need to check their balance as the _convert() below will do a safe subtraction which requires // the subtraction to not overflow, which would happen if their balance is not sufficient. _convert(args, bridgeName); // Let the DApps know there was a Synth exchange emit SynthExchange( args.fromAccount, args.destAccount, args.sourceCurrencyKey, args.sourceAmount, args.destCurrencyKey, amountReceived, args.fee, args.destChainId ); // Emit separate event to track atomic exchanges emit AtomicSynthExchange( args.fromAccount, args.destAccount, args.sourceCurrencyKey, args.sourceAmount, args.destCurrencyKey, amountReceived, args.fee, args.destChainId ); } function _checkAndUpdateAtomicVolume(uint256 sourceSusdValue) internal { uint256 currentVolume = uint256(lastAtomicVolume.time) == block.timestamp ? uint256(lastAtomicVolume.volume).add(sourceSusdValue) : sourceSusdValue; require(currentVolume <= getAtomicMaxVolumePerBlock(), "Surpassed volume limit"); lastAtomicVolume.time = uint64(block.timestamp); lastAtomicVolume.volume = uint192(currentVolume); // Protected by volume limit check above } function _feeRateForAtomicExchange( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) internal view returns (uint256) { // Get the exchange fee rate as per source and destination currencyKey uint256 baseRate = getAtomicExchangeFeeRate(sourceCurrencyKey).add(getAtomicExchangeFeeRate(destinationCurrencyKey)); if (baseRate == 0) { // If no atomic rate was set, fallback to the regular exchange rate baseRate = getExchangeFeeRate(sourceCurrencyKey).add(getExchangeFeeRate(destinationCurrencyKey)); } return baseRate; } function _getAmountsForAtomicExchangeMinusFees( uint256 sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) internal view returns ( uint256 amountReceived, uint256 fee, uint256 exchangeFeeRate, uint256 systemConvertedAmount, uint256 systemSourceRate, uint256 systemDestinationRate ) { uint256 destinationAmount; (destinationAmount, systemConvertedAmount, systemSourceRate, systemDestinationRate) = exchangeRates() .effectiveAtomicValueAndRates(sourceCurrencyKey, sourceAmount, destinationCurrencyKey); exchangeFeeRate = _feeRateForAtomicExchange(sourceCurrencyKey, destinationCurrencyKey); amountReceived = _deductFeesFromAmount(destinationAmount, exchangeFeeRate); fee = destinationAmount.sub(amountReceived); } event AtomicSynthExchange( address indexed account, address indexed toAddress, bytes32 fromCurrencyKey, uint256 fromAmount, bytes32 toCurrencyKey, uint256 toAmount, uint256 fee, uint16 destChainId ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IAddressResolver { function getAddress(bytes32 name) external view returns (address); function getSynth(bytes32 key) external view returns (address); function getAvailableBridge(bytes32 bridgeName) external view returns (address); function getBridgeList() external view returns (bytes32[] memory); function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; 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 (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); // Mutative functions function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); // Events event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IExchangeCircuitBreaker { // Views function exchangeRates() external view returns (address); function rateWithInvalid(bytes32 currencyKey) external view returns (uint256, bool); function priceDeviationThresholdFactor() external view returns (uint256); function isDeviationAboveThreshold(uint256 base, uint256 comparison) external view returns (bool); function lastExchangeRate(bytes32 currencyKey) external view returns (uint256); // Mutative functions function resetLastExchangeRate(bytes32[] calldata currencyKeys) external; function rateWithBreakCircuit(bytes32 currencyKey) external returns (uint256 lastValidRate, bool circuitBroken); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IExchanger { struct ExchangeEntrySettlement { bytes32 src; uint256 amount; bytes32 dest; uint256 reclaim; uint256 rebate; uint256 srcRoundIdAtPeriodEnd; uint256 destRoundIdAtPeriodEnd; uint256 timestamp; } struct ExchangeEntry { uint256 sourceRate; uint256 destinationRate; uint256 destinationAmount; uint256 exchangeFeeRate; uint256 exchangeDynamicFeeRate; uint256 roundIdForSrc; uint256 roundIdForDest; } struct ExchangeArgs { address fromAccount; address destAccount; bytes32 sourceCurrencyKey; bytes32 destCurrencyKey; uint256 sourceAmount; uint256 destAmount; uint256 fee; uint256 reclaimed; uint256 refunded; uint16 destChainId; bool erc20Payment; } // Views function calculateAmountAfterSettlement( address from, bytes32 currencyKey, uint256 amount, uint256 refunded ) external view returns (uint256 amountAfterSettlement); function isSynthRateInvalid(bytes32 currencyKey) external view returns (bool); function maxSecsLeftInWaitingPeriod(address account, bytes32 currencyKey) external view returns (uint256); function settlementOwing( address account, bytes32 currencyKey ) external view returns (uint256 reclaimAmount, uint256 rebateAmount, uint256 numEntries); // function hasWaitingPeriodOrSettlementOwing(address account, bytes32 currencyKey) external view returns (bool); function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint256); function dynamicFeeRateForExchange( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns (uint256 feeRate, bool tooVolatile); function getAmountsForExchange( uint256 sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns (uint256 amountReceived, uint256 fee, uint256 exchangeFeeRate); // function priceDeviationThresholdFactor() external view returns (uint256); // function waitingPeriodSecs() external view returns (uint256); // function lastExchangeRate(bytes32 currencyKey) external view returns (uint256); // Mutative functions function exchange(ExchangeArgs calldata args, bytes32 bridgeName) external payable returns (uint256 amountReceived); function exchangeAtomically( uint256 minAmount, ExchangeArgs calldata args, bytes32 bridgeName ) external payable returns (uint256 amountReceived); function settle(address from, bytes32 currencyKey) external returns (uint256 reclaimed, uint256 refunded, uint256 numEntries); function suspendSynthWithInvalidRate(bytes32 currencyKey) external; function updateDestinationForExchange(address recipient, bytes32 destinationKey, uint256 destinationAmount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; 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, uint256[] calldata roundIds) external view returns (bool); function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory); function effectiveValue( bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint256 value); function effectiveValueAndRates( bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint256 value, uint256 sourceRate, uint256 destinationRate); function effectiveValueAndRatesAtRound( bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey, uint256 roundIdForSrc, uint256 roundIdForDest ) external view returns (uint256 value, uint256 sourceRate, uint256 destinationRate); function effectiveAtomicValueAndRates( bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint256 value, uint256 systemValue, uint256 systemSourceRate, uint256 systemDestinationRate); function getCurrentRoundId(bytes32 currencyKey) external view returns (uint256); function getLastRoundIdBeforeElapsedSecs( bytes32 currencyKey, uint256 startingRoundId, uint256 startingTimestamp, uint256 timediff ) external view returns (uint256); function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256); function rateAndTimestampAtRound(bytes32 currencyKey, uint256 roundId) external view returns (uint256 rate, uint256 time); function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint256 rate, uint256 time); function rateAndInvalid(bytes32 currencyKey) external view returns (uint256 rate, bool isInvalid); function rateForCurrency(bytes32 currencyKey) external view returns (uint256); 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 (uint256); function ratesAndUpdatedTimeForCurrencyLastNRounds( bytes32 currencyKey, uint256 numRounds, uint256 roundId ) external view returns (uint256[] memory rates, uint256[] memory times); function ratesAndInvalidForCurrencies( bytes32[] calldata currencyKeys ) external view returns (uint256[] memory rates, bool anyRateInvalid); function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint256[] memory); function synthTooVolatileForAtomicExchange(bytes32 currencyKey) external view returns (bool); function rateWithSafetyChecks(bytes32 currencyKey) external returns (uint256 rate, bool broken, bool invalid); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IExchangeState { // Views struct ExchangeEntry { bytes32 src; uint256 amount; bytes32 dest; uint256 amountReceived; uint256 exchangeFeeRate; uint256 timestamp; uint256 roundIdForSrc; uint256 roundIdForDest; } function getLengthOfEntries(address account, bytes32 currencyKey) external view returns (uint256); function getEntryAt( address account, bytes32 currencyKey, uint256 index ) external view returns ( bytes32 src, uint256 amount, bytes32 dest, uint256 amountReceived, uint256 exchangeFeeRate, uint256 timestamp, uint256 roundIdForSrc, uint256 roundIdForDest ); function getMaxTimestamp(address account, bytes32 currencyKey) external view returns (uint256); // Mutative functions function appendExchangeEntry( address account, bytes32 src, uint256 amount, bytes32 dest, uint256 amountReceived, uint256 exchangeFeeRate, uint256 timestamp, uint256 roundIdForSrc, uint256 roundIdForDest ) external; function removeEntries(address account, bytes32 currencyKey) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IFlexibleStorage { // Views function getUIntValue(bytes32 contractName, bytes32 record) external view returns (uint256); function getUIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (uint256[] memory); function getIntValue(bytes32 contractName, bytes32 record) external view returns (int256); function getIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (int256[] 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, uint256 value) external; function setUIntValues(bytes32 contractName, bytes32[] calldata records, uint256[] calldata values) external; function setIntValue(bytes32 contractName, bytes32 record, int256 value) external; function setIntValues(bytes32 contractName, bytes32[] calldata records, int256[] 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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interfaces/ISynth.sol"; interface IIssuer { // Views function allNetworksDebtInfo() external view returns (uint256 debt, uint256 sharesSupply); function availableCurrencyKeys() external view returns (bytes32[] memory); function availableSynthCount() external view returns (uint256); function availableSynths(uint256 index) external view returns (ISynth); function canBurnSynths(address account) external view returns (bool); function collateral(address account) external view returns (uint256); function collateralisationRatio(address issuer) external view returns (uint256); function collateralisationRatioAndAnyRatesInvalid( address _issuer ) external view returns (uint256 cratio, bool anyRateIsInvalid); function debtBalanceOf(address issuer) external view returns (uint256 debtBalance); function issuanceRatio() external view returns (uint256); function lastIssueEvent(address account) external view returns (uint256); function maxIssuableSynths(address issuer) external view returns (uint256 maxIssuable); function minimumStakeTime() external view returns (uint256); function remainingIssuableSynths( address issuer ) external view returns (uint256 maxIssuable, uint256 alreadyIssued, uint256 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) external view returns (uint256); function checkFreeCollateral( address _issuer, bytes32 _collateralKey, uint16 _chainId ) external view returns (uint256 withdrawableSynthr); function issueSynths( address from, uint256 amount, uint256 destChainId ) external returns (uint256 synthAmount, uint256 debtShare); function issueMaxSynths(address from, uint256 destChainId) external returns (uint256 synthAmount, uint256 debtShare); function burnSynths( address from, bytes32 synthKey, uint256 amount ) external returns (uint256 synthAmount, uint256 debtShare, uint256 reclaimed, uint256 refunded); function burnSynthsToTarget( address from, bytes32 synthKey ) external returns (uint256 synthAmount, uint256 debtShare, uint256 reclaimed, uint256 refunded); function burnForRedemption(address deprecatedSynthProxy, address account, uint256 balance) external; function burnSynthsWithoutDebt(bytes32 currencyKey, address from, uint amount) external returns (uint256 burnAmount); function synthIssueFromSynthrSwap(address _account, bytes32 _synthKey, uint256 _synthAmount) external; function liquidateAccount( address account, bytes32 collateralKey, uint16 chainId, bool isSelfLiquidation ) external returns (uint256 totalRedeemed, uint256 amountToLiquidate, uint256 sharesToRemove); function destIssue(address _account, bytes32 _synthKey, uint256 _synthAmount) external; function destBurn(address _account, bytes32 _synthKey, uint256 _synthAmount) external returns (uint256); function transferMargin(address account, uint256 marginDelta) external returns (uint256); function destTransferMargin(address _account, uint256 _marginDelta, bytes32 _marketKey) external returns (bool); function setCurrentPeriodId(uint128 periodId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ISynth { // Views function balanceOf(address _account) external view returns (uint256); function currencyKey() external view returns (bytes32); function transferableSynths(address account) external view returns (uint256); // Mutative functions function transferAndSettle(address to, uint256 value) external payable returns (bool); function transferFromAndSettle(address from, address to, uint256 value) external payable returns (bool); function burn(address account, uint256 amount) external; function issue(address account, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IExchanger.sol"; interface ISynthrBridge { /* ========== MUTATIVE FUNCTIONS ========== */ function sendDepositCollateral(address account, bytes32 collateralKey, uint256 amount, bool erc20Payment) external payable; function sendBurn(address account, bytes32 synthKey, uint256 amount, bool erc20Payment) external payable; function sendExchange( address account, bytes32 srcSynthKey, bytes32 dstSynthKey, uint256 srcAmount, uint256 dstAmount, uint256 reclaimed, uint256 refunded, uint256 fee, uint16 dstChainId, bool erc20Payment ) external payable; function sendBridgeSyToken( address account, bytes32 synthKey, uint256 amount, uint16 dstChainId, bool erc20Payment ) external payable; function sendTransferMargin(address account, uint256 amount, bytes32 marketKey, bool erc20Payment) external payable; function sendCrossSwapSyAssetToNative( address account, bytes32 srcKey, uint256 srcAmount, bytes32 dstKey, uint256 dstAmount, uint16 dstChainId, uint256 fee, bytes calldata dexPayload, address dexAddress, bool erc20Payment ) external payable; function sendCrossSwapNativeToSyAsset( address account, bytes32 srcKey, uint256 srcAmount, bytes32 dstKey, uint256 dstAmount, uint16 dstChainId, uint256 fee, bool erc20Payment ) external payable; function sendCrossSwapNativeToNative( address account, bytes32 srcKey, uint256 srcAmount, bytes32 dstKey, uint256 dstAmount, uint16 dstChainId, uint256 fee, address dexAddress, bytes calldata dexPayload, bool erc20Payment ) external payable; function sendCrossSwapSyAssetToNativeWithDex( address account, bytes32 srcKey, uint256 srcAmount, bytes32 dstKey, uint256 dstAmount, uint16 dstChainId, uint256 fee, bool erc20Payment ) external payable; function sendCrossSwapNativeToNativeWithDex( address account, bytes32 srcKey, uint256 srcAmount, bytes32 dstKey, uint256 dstAmount, uint16 dstChainId, uint256 fee, bool erc20Payment ) external payable; // function sendExchange(IExchanger.ExchangeArgs calldata args) external payable; function calcFee(bytes memory lzPayload, uint16 packetType, uint16 dstChainId) external view returns (uint256 lzFee); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ISystemStatus { struct Status { bool canSuspend; bool canResume; } struct Suspension { bool suspended; // reason is an integer code, // 0 => no reason, 1 => upgrading, 2+ => defined by system usage uint248 reason; } // Views function accessControl(bytes32 section, address account) external view returns (bool canSuspend, bool canResume); function requireSystemActive() external view; function systemSuspended() external view returns (bool); function requireIssuanceActive() external view; function requireExchangeActive() external view; function requireFuturesActive() external view; function requireFuturesMarketActive(bytes32 marketKey) external view; function requireExchangeBetweenSynthsAllowed(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view; function requireSynthActive(bytes32 currencyKey) external view; function synthSuspended(bytes32 currencyKey) external view returns (bool); function requireSynthsActive(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view; function systemSuspension() external view returns (bool suspended, uint248 reason); function issuanceSuspension() external view returns (bool suspended, uint248 reason); function exchangeSuspension() external view returns (bool suspended, uint248 reason); function futuresSuspension() external view returns (bool suspended, uint248 reason); function synthExchangeSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason); function synthSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason); function futuresMarketSuspension(bytes32 marketKey) external view returns (bool suspended, uint248 reason); function getSynthExchangeSuspensions( bytes32[] calldata synths ) external view returns (bool[] memory exchangeSuspensions, uint256[] memory reasons); function getSynthSuspensions( bytes32[] calldata synths ) external view returns (bool[] memory suspensions, uint256[] memory reasons); function getFuturesMarketSuspensions( bytes32[] calldata marketKeys ) external view returns (bool[] memory suspensions, uint256[] memory reasons); // Restricted functions function suspendIssuance(uint256 reason) external; function suspendSynth(bytes32 currencyKey, uint256 reason) external; function suspendFuturesMarket(bytes32 marketKey, uint256 reason) external; function updateAccessControl(bytes32 section, address account, bool canSuspend, bool canResume) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./ISynth.sol"; interface IWrappedSynthr { // Views function isWaitingPeriod(bytes32 currencyKey) external view returns (bool); function chainBalanceOf(address account, uint16 _chainId) external view returns (uint256); function chainBalanceOfPerKey(address _account, bytes32 _collateralKey, uint16 _chainId) external view returns (uint256); function balanceOf(address account) external view returns (uint256); function collateralCurrency(bytes32 _collateralKey) external view returns (address); function getAvailableCollaterals() external view returns (bytes32[] memory); // Mutative Functions function burnSynths(uint256 amount, bytes32 synthKey) external; function withdrawCollateral(bytes32 collateralKey, uint256 collateralAmount) external; function burnSynthsToTarget(bytes32 synthKey) external; function destBurn(address _account, bytes32 _synthKey, uint256 _synthAmount) external; function exchange( bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey, uint16 destChainId ) external returns (uint256 amountReceived); function exchangeWithTracking( bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey, address rewardAddress, bytes32 trackingCode, uint16 destChainId ) external payable returns (uint256 amountReceived); // function exchangeWithTrackingForInitiator( // bytes32 sourceCurrencyKey, // uint256 sourceAmount, // bytes32 destinationCurrencyKey, // address rewardAddress, // bytes32 trackingCode, // uint16 destChainId // ) external payable returns (uint256 amountReceived); function exchangeOnBehalfWithTracking( address exchangeForAddress, bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey, address rewardAddress, bytes32 trackingCode, uint16 destChainId ) external returns (uint256 amountReceived); function exchangeAtomically( bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey, bytes32 trackingCode, uint256 minAmount, uint16 destChainId ) external payable returns (uint256 amountReceived); function issueMaxSynths(uint16 destChainId) external payable; function issueSynths(bytes32 currencyKey, uint256 amount, uint256 synthToMint, uint16 destChainId) external payable; // Liquidations function liquidateDelinquentAccount(address account, bytes32 collateralKey) external returns (bool); function liquidateSelf(bytes32 collateralKey) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Inheritance import "./Owned.sol"; import "../interfaces/IAddressResolver.sol"; // Internal references import "../interfaces/IIssuer.sol"; import "./MixinResolver.sol"; contract AddressResolverLightChain is Owned, IAddressResolver { mapping(bytes32 => address) public repository; mapping(bytes32 => address) public availableBridge; mapping(address => bool) public isBridge; bytes32[] public bridgeList; constructor(address _owner) Owned(_owner) {} /* ========== RESTRICTED FUNCTIONS ========== */ function importAddresses(bytes32[] calldata names, address[] calldata destinations) external onlyOwner { require(names.length == destinations.length, "Input lengths must match"); for (uint256 i = 0; i < names.length; i++) { bytes32 name = names[i]; address destination = destinations[i]; repository[name] = destination; emit AddressImported(name, destination); } } function addAvailableBridge(bytes32 bridgeName, address bridgeAddress) external onlyOwner { _addAvailableBridge(bridgeName, bridgeAddress); } function removeAvailableBridge(bytes32 bridgeName) external onlyOwner { _removeAvailableBridge(bridgeName); } /* ========= PUBLIC FUNCTIONS ========== */ function rebuildCaches(MixinResolver[] calldata destinations) external { for (uint256 i = 0; i < destinations.length; i++) { destinations[i].rebuildCache(); } } /* ========== PRIVATE FUNCTIONS ========== */ function _addAvailableBridge(bytes32 bridgeName, address bridgeAddress) private { if (availableBridge[bridgeName] != address(0)) { _removeAvailableBridge(bridgeName); } availableBridge[bridgeName] = bridgeAddress; isBridge[bridgeAddress] = true; bridgeList.push(bridgeName); emit AddBridge(bridgeName, bridgeAddress); } function _removeAvailableBridge(bytes32 bridgeName) private { require(availableBridge[bridgeName] != address(0), "The bridge no exist."); uint lastBridgeNumber = bridgeList.length - 1; for (uint ii = 0; ii <= lastBridgeNumber; ii++) { if (bridgeList[ii] == bridgeName) { bridgeList[ii] = bridgeList[lastBridgeNumber]; bridgeList.pop(); break; } } address bridgeToRemove = availableBridge[bridgeName]; delete availableBridge[bridgeName]; delete isBridge[bridgeToRemove]; emit RemoveBridge(bridgeName, bridgeToRemove); } /* ========== VIEWS ========== */ function areAddressesImported(bytes32[] calldata names, address[] calldata destinations) external view returns (bool) { for (uint256 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)); } function getAvailableBridge(bytes32 bridgeName) external view returns (address) { return availableBridge[bridgeName]; } function getBridgeList() external view returns (bytes32[] memory) { return bridgeList; } /* ========== EVENTS ========== */ event AddressImported(bytes32 name, address destination); event AddBridge(bytes32 indexed bridgeName, address bridgeAddress); event RemoveBridge(bytes32 indexed bridgeName, address bridgeAddress); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Inheritance import "./Owned.sol"; import "./MixinResolver.sol"; import "./MixinSystemSettings.sol"; import "../interfaces/IExchanger.sol"; // Libraries import "./SafeDecimalMath.sol"; // Internal references import "../interfaces/ISystemStatus.sol"; import "../interfaces/IERC20.sol"; import "../interfaces/IExchangeState.sol"; import "../interfaces/IExchangeRates.sol"; import "../interfaces/IExchangeCircuitBreaker.sol"; import "../interfaces/IWrappedSynthr.sol"; import "../interfaces/IIssuer.sol"; import "../interfaces/ISynthrBridgeLightChain.sol"; contract Exchanger is Owned, MixinSystemSettings { using SafeMath for uint256; using SafeDecimalMath for uint256; bytes32 public constant CONTRACT_NAME = "Exchanger"; bytes32 internal constant sUSD = "sUSD"; /* ========== ADDRESS RESOLVER CONFIGURATION ========== */ bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus"; bytes32 private constant CONTRACT_EXCHANGESTATE = "ExchangeState"; bytes32 private constant CONTRACT_EXRATES = "ExchangeRates"; bytes32 private constant CONTRACT_WRAPPED_SYNTHR = "WrappedSynthr"; bytes32 private constant CONTRACT_ISSUER = "Issuer"; bytes32 private constant CONTRACT_CIRCUIT_BREAKER = "ExchangeCircuitBreaker"; constructor(address _owner, address _resolver) Owned(_owner) MixinSystemSettings(_resolver) {} /* ========== VIEWS ========== */ function resolverAddressesRequired() public view override returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](6); newAddresses[0] = CONTRACT_SYSTEMSTATUS; newAddresses[1] = CONTRACT_EXCHANGESTATE; newAddresses[2] = CONTRACT_EXRATES; newAddresses[3] = CONTRACT_WRAPPED_SYNTHR; newAddresses[4] = CONTRACT_ISSUER; newAddresses[5] = CONTRACT_CIRCUIT_BREAKER; addresses = combineArrays(existingAddresses, newAddresses); } function systemStatus() internal view returns (ISystemStatus) { return ISystemStatus(requireAndGetAddress(CONTRACT_SYSTEMSTATUS)); } function exchangeState() internal view returns (IExchangeState) { return IExchangeState(requireAndGetAddress(CONTRACT_EXCHANGESTATE)); } function exchangeRates() internal view returns (IExchangeRates) { return IExchangeRates(requireAndGetAddress(CONTRACT_EXRATES)); } function synthrBridge(bytes32 bridgeName) internal view returns (ISynthrBridge) { return ISynthrBridge(resolver.getAvailableBridge(bridgeName)); } function exchangeCircuitBreaker() internal view returns (IExchangeCircuitBreaker) { return IExchangeCircuitBreaker(requireAndGetAddress(CONTRACT_CIRCUIT_BREAKER)); } function wrappedSynthr() internal view returns (IWrappedSynthr) { return IWrappedSynthr(requireAndGetAddress(CONTRACT_WRAPPED_SYNTHR)); } function issuer() internal view returns (IIssuer) { return IIssuer(requireAndGetAddress(CONTRACT_ISSUER)); } function maxSecsLeftInWaitingPeriod(address account, bytes32 currencyKey) public view returns (uint256) { return secsLeftInWaitingPeriodForExchange(exchangeState().getMaxTimestamp(account, currencyKey)); } function settlementOwing( address account, bytes32 currencyKey ) public view returns (uint256 reclaimAmount, uint256 rebateAmount, uint256 numEntries) { (reclaimAmount, rebateAmount, numEntries, ) = _settlementOwing(account, currencyKey); } // Internal function to aggregate each individual rebate and reclaim entry for a synth function _settlementOwing( address account, bytes32 currencyKey ) internal view returns (uint256 reclaimAmount, uint256 rebateAmount, uint256 numEntries, IExchanger.ExchangeEntrySettlement[] memory) { // Need to sum up all reclaim and rebate amounts for the user and the currency key numEntries = exchangeState().getLengthOfEntries(account, currencyKey); // For each unsettled exchange IExchanger.ExchangeEntrySettlement[] memory settlements = new IExchanger.ExchangeEntrySettlement[](numEntries); for (uint256 i = 0; i < numEntries; i++) { uint256 reclaims; uint256 rebate; // fetch the entry from storage IExchangeState.ExchangeEntry memory exchangeEntry = _getExchangeEntry(account, currencyKey, i); // determine the last round ids for src and dest pairs when period ended or latest if not over (uint256 srcRoundIdAtPeriodEnd, uint256 destRoundIdAtPeriodEnd) = getRoundIdsAtPeriodEnd(exchangeEntry); // given these round ids, determine what effective value they should have received (uint256 destinationAmount, , ) = exchangeRates().effectiveValueAndRatesAtRound( exchangeEntry.src, exchangeEntry.amount, exchangeEntry.dest, srcRoundIdAtPeriodEnd, destRoundIdAtPeriodEnd ); // and deduct the fee from this amount using the exchangeFeeRate from storage uint256 amountShouldHaveReceived = _deductFeesFromAmount(destinationAmount, exchangeEntry.exchangeFeeRate); // SIP-65 settlements where the amount at end of waiting period is beyond the threshold, then // settle with no reclaim or rebate bool sip65condition = exchangeCircuitBreaker().isDeviationAboveThreshold( exchangeEntry.amountReceived, amountShouldHaveReceived ); if (!sip65condition) { if (exchangeEntry.amountReceived > amountShouldHaveReceived) { // if they received more than they should have, add to the reclaim tally reclaims = exchangeEntry.amountReceived.sub(amountShouldHaveReceived); reclaimAmount = reclaimAmount.add(reclaims); } else if (amountShouldHaveReceived > exchangeEntry.amountReceived) { // if less, add to the rebate tally rebate = amountShouldHaveReceived.sub(exchangeEntry.amountReceived); rebateAmount = rebateAmount.add(rebate); } } settlements[i] = IExchanger.ExchangeEntrySettlement({ src: exchangeEntry.src, amount: exchangeEntry.amount, dest: exchangeEntry.dest, reclaim: reclaims, rebate: rebate, srcRoundIdAtPeriodEnd: srcRoundIdAtPeriodEnd, destRoundIdAtPeriodEnd: destRoundIdAtPeriodEnd, timestamp: exchangeEntry.timestamp }); } return (reclaimAmount, rebateAmount, numEntries, settlements); } function _getExchangeEntry( address account, bytes32 currencyKey, uint256 index ) internal view returns (IExchangeState.ExchangeEntry memory) { ( bytes32 src, uint256 amount, bytes32 dest, uint256 amountReceived, uint256 exchangeFeeRate, uint256 timestamp, uint256 roundIdForSrc, uint256 roundIdForDest ) = exchangeState().getEntryAt(account, currencyKey, index); return IExchangeState.ExchangeEntry({ src: src, amount: amount, dest: dest, amountReceived: amountReceived, exchangeFeeRate: exchangeFeeRate, timestamp: timestamp, roundIdForSrc: roundIdForSrc, roundIdForDest: roundIdForDest }); } /* ========== SETTERS ========== */ function calculateAmountAfterSettlement( address from, bytes32 currencyKey, uint256 amount, uint256 refunded ) public view returns (uint256 amountAfterSettlement) { amountAfterSettlement = amount; // balance of a synth will show an amount after settlement uint256 balanceOfSourceAfterSettlement = IERC20(address(issuer().synths(currencyKey))).balanceOf(from); if (refunded > 0) { amountAfterSettlement = amountAfterSettlement.add(refunded); } // when there isn't enough supply (either due to reclamation settlement or because the number is too high) if (amountAfterSettlement > balanceOfSourceAfterSettlement) { // then the amount to exchange is reduced to their remaining supply amountAfterSettlement = balanceOfSourceAfterSettlement; } } function isSynthRateInvalid(bytes32 currencyKey) external view returns (bool) { (, bool invalid) = exchangeCircuitBreaker().rateWithInvalid(currencyKey); return invalid; } /* ========== MUTATIVE FUNCTIONS ========== */ function exchange( IExchanger.ExchangeArgs calldata args, bytes32 bridgeName ) external payable onlyWrappedSynthrorSynth returns (uint256 amountReceived) { (amountReceived, ) = _exchange(args, bridgeName); } function updateDestinationForExchange( address recipient, bytes32 destinationKey, uint256 destinationAmount ) public onlySynthrBridge { require(destinationKey != bytes32(0), "dest key didn't set."); ISynth dest = issuer().synths(destinationKey); dest.issue(recipient, destinationAmount); emit DestIssueForExchange(recipient, destinationKey, destinationAmount); } function _settleAndCalcSourceAmountRemaining( uint256 sourceAmount, address from, bytes32 sourceCurrencyKey ) internal returns (uint256 sourceAmountAfterSettlement, uint256 reclaimed, uint256 refunded) { uint256 numEntriesSettled; (reclaimed, refunded, numEntriesSettled) = _internalSettle(from, sourceCurrencyKey); sourceAmountAfterSettlement = sourceAmount; // when settlement was required if (numEntriesSettled > 0) { // ensure the sourceAmount takes this into account sourceAmountAfterSettlement = calculateAmountAfterSettlement(from, sourceCurrencyKey, sourceAmount, refunded); } } function _exchange( IExchanger.ExchangeArgs memory args, bytes32 bridgeName ) internal returns (uint256 amountReceived, uint256 fee) { require(args.sourceAmount > 0, "Zero amount"); // Using struct to resolve stack too deep error IExchanger.ExchangeEntry memory entry; entry.roundIdForSrc = exchangeRates().getCurrentRoundId(args.sourceCurrencyKey); entry.roundIdForDest = exchangeRates().getCurrentRoundId(args.destCurrencyKey); (args.sourceAmount, args.reclaimed, args.refunded) = _settleAndCalcSourceAmountRemaining( args.sourceAmount, args.fromAccount, args.sourceCurrencyKey ); // If, after settlement the user has no balance left (highly unlikely), then return to prevent // emitting events of 0 and don't revert so as to ensure the settlement queue is emptied if (args.sourceAmount == 0) { return (0, 0); } (entry.destinationAmount, entry.sourceRate, entry.destinationRate) = exchangeRates().effectiveValueAndRatesAtRound( args.sourceCurrencyKey, args.sourceAmount, args.destCurrencyKey, entry.roundIdForSrc, entry.roundIdForDest ); _ensureCanExchangeAtRound(args.sourceCurrencyKey, args.destCurrencyKey, entry.roundIdForSrc, entry.roundIdForDest); // SIP-65: Decentralized Circuit Breaker // mutative call to suspend system if the rate is invalid if (_exchangeRatesCircuitBroken(args.sourceCurrencyKey, args.destCurrencyKey)) { return (0, 0); } bool tooVolatile; (entry.exchangeFeeRate, tooVolatile) = _feeRateForExchangeAtRounds( args.sourceCurrencyKey, args.destCurrencyKey, entry.roundIdForSrc, entry.roundIdForDest ); if (tooVolatile) { // do not exchange if rates are too volatile, this to prevent charging // dynamic fees that are over the max value return (0, 0); } amountReceived = _deductFeesFromAmount(entry.destinationAmount, entry.exchangeFeeRate); // Note: `fee` is denominated in the destinationCurrencyKey. fee = entry.destinationAmount.sub(amountReceived); args.destAmount = amountReceived; args.fee = fee; // Note: We don't need to check their balance as the _convert() below will do a safe subtraction which requires // the subtraction to not overflow, which would happen if their balance is not sufficient. _convert(args, bridgeName); // Let the DApps know there was a Synth exchange emit SynthExchange( args.fromAccount, args.destAccount, args.sourceCurrencyKey, args.sourceAmount, args.destCurrencyKey, amountReceived, args.fee, args.destChainId ); // Emit separate event to track tracking exchanges emit TrackingSynthExchange( args.fromAccount, args.destAccount, args.sourceCurrencyKey, args.sourceAmount, args.destCurrencyKey, amountReceived, args.fee, args.destChainId ); // if the waiting period is gt 0 if (getWaitingPeriodSecs() > 0) { // persist the exchange information for the dest key appendExchange( args.destAccount, args.sourceCurrencyKey, args.sourceAmount, args.destCurrencyKey, amountReceived, entry.exchangeFeeRate ); } } // SIP-65: Decentralized Circuit Breaker function _exchangeRatesCircuitBroken( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) internal returns (bool circuitBroken) { // check both currencies unless they're sUSD, since its rate is never invalid (gas savings) if (sourceCurrencyKey != sUSD) { (, circuitBroken) = exchangeCircuitBreaker().rateWithBreakCircuit(sourceCurrencyKey); } if (destinationCurrencyKey != sUSD) { // we're not skipping the suspension check if the circuit was broken already // this is not terribly important, but is more consistent (so that results don't // depend on which synth is source and which is destination) bool destCircuitBroken; (, destCircuitBroken) = exchangeCircuitBreaker().rateWithBreakCircuit(destinationCurrencyKey); circuitBroken = circuitBroken || destCircuitBroken; } } function _convert( IExchanger.ExchangeArgs memory args, // uint256 sourceAmountAfterSettlement, // uint256 amountReceived, // uint256 fee, bytes32 bridgeName ) internal { // Burn the source amount issuer().synths(args.sourceCurrencyKey).burn(args.fromAccount, args.sourceAmount); if (args.destChainId == 0) { ISynth dest = issuer().synths(args.destCurrencyKey); dest.issue(args.destAccount, args.destAmount); } if (args.fee > 0 && args.destCurrencyKey != sUSD) { // Normalize fee to sUSD // Note: `fee` is being reused to avoid stack too deep errors. args.fee = exchangeRates().effectiveValue(args.destCurrencyKey, args.fee, sUSD); } synthrBridge(bridgeName).sendExchange{value: msg.value}( args.fromAccount, args.sourceCurrencyKey, args.destCurrencyKey, args.sourceAmount, args.destAmount, args.reclaimed, args.refunded, args.fee, args.destChainId, args.erc20Payment ); } // Note: this function can intentionally be called by anyone on behalf of anyone else (the caller just pays the gas) function settle( address from, bytes32 currencyKey ) external returns (uint256 reclaimed, uint256 refunded, uint256 numEntriesSettled) { systemStatus().requireSynthActive(currencyKey); return _internalSettle(from, currencyKey); } function suspendSynthWithInvalidRate(bytes32 currencyKey) external { systemStatus().requireSystemActive(); // SIP-65: Decentralized Circuit Breaker (, bool circuitBroken) = exchangeCircuitBreaker().rateWithBreakCircuit(currencyKey); require(circuitBroken, "Synth price is valid"); } /* ========== INTERNAL FUNCTIONS ========== */ function _ensureCanExchange(bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey) internal view { // require(sourceCurrencyKey != destinationCurrencyKey, "Can't be same synth"); require(sourceAmount > 0, "Zero amount"); bytes32[] memory synthKeys = new bytes32[](2); synthKeys[0] = sourceCurrencyKey; synthKeys[1] = destinationCurrencyKey; require(!exchangeRates().anyRateIsInvalid(synthKeys), "src/dest value is invalid."); } function _ensureCanExchangeAtRound( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey, uint256 roundIdForSrc, uint256 roundIdForDest ) internal view { // require(sourceCurrencyKey != destinationCurrencyKey, "Can't be same synth"); bytes32[] memory synthKeys = new bytes32[](2); synthKeys[0] = sourceCurrencyKey; synthKeys[1] = destinationCurrencyKey; uint256[] memory roundIds = new uint256[](2); roundIds[0] = roundIdForSrc; roundIds[1] = roundIdForDest; require(!exchangeRates().anyRateIsInvalidAtRound(synthKeys, roundIds), "src/dest value is invalid."); } function _internalSettle( address from, bytes32 currencyKey ) internal returns (uint256 reclaimed, uint256 refunded, uint256 numEntriesSettled) { require(maxSecsLeftInWaitingPeriod(from, currencyKey) == 0, "Cannot settle during waiting period"); ( uint256 reclaimAmount, uint256 rebateAmount, uint256 entries, IExchanger.ExchangeEntrySettlement[] memory settlements ) = _settlementOwing(from, currencyKey); if (reclaimAmount > rebateAmount) { reclaimed = reclaimAmount.sub(rebateAmount); reclaim(from, currencyKey, reclaimed); } else if (rebateAmount > reclaimAmount) { refunded = rebateAmount.sub(reclaimAmount); refund(from, currencyKey, refunded); } // // by checking a reclaim or refund we also check that the currency key is still a valid synth, // // as the deviation check will return 0 if the synth has been removed. // if (updateCache && (reclaimed > 0 || refunded > 0)) { // bytes32[] memory key = new bytes32[](1); // key[0] = currencyKey; // debtCache().updateCachedSynthDebts(key); // } // emit settlement event for each settled exchange entry for (uint256 i = 0; i < settlements.length; i++) { emit ExchangeEntrySettled( from, settlements[i].src, settlements[i].amount, settlements[i].dest, settlements[i].reclaim, settlements[i].rebate, settlements[i].srcRoundIdAtPeriodEnd, settlements[i].destRoundIdAtPeriodEnd, settlements[i].timestamp ); } numEntriesSettled = entries; // Now remove all entries, even if no reclaim and no rebate exchangeState().removeEntries(from, currencyKey); } function reclaim(address from, bytes32 currencyKey, uint256 amount) internal { // burn amount from user issuer().synths(currencyKey).burn(from, amount); emit ExchangeReclaim(from, currencyKey, amount); } function refund(address from, bytes32 currencyKey, uint256 amount) internal { // issue amount to user issuer().synths(currencyKey).issue(from, amount); emit ExchangeRebate(from, currencyKey, amount); } function secsLeftInWaitingPeriodForExchange(uint256 timestamp) internal view returns (uint256) { uint256 _waitingPeriodSecs = getWaitingPeriodSecs(); if (timestamp == 0 || block.timestamp >= timestamp.add(_waitingPeriodSecs)) { return 0; } return timestamp.add(_waitingPeriodSecs).sub(block.timestamp); } /* ========== Exchange Related Fees ========== */ /// @notice public function to get the total fee rate for a given exchange /// @param sourceCurrencyKey The source currency key /// @param destinationCurrencyKey The destination currency key /// @return The exchange fee rate, and whether the rates are too volatile function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view returns (uint256) { (uint256 feeRate, bool tooVolatile) = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey); require(!tooVolatile, "too volatile"); return feeRate; } /// @notice public function to get the dynamic fee rate for a given exchange /// @param sourceCurrencyKey The source currency key /// @param destinationCurrencyKey The destination currency key /// @return feeRate The exchange dynamic fee rate /// @return tooVolatile if rates are too volatile function dynamicFeeRateForExchange( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns (uint256 feeRate, bool tooVolatile) { return _dynamicFeeRateForExchange(sourceCurrencyKey, destinationCurrencyKey); } /// @notice Calculate the exchange fee for a given source and destination currency key /// @param sourceCurrencyKey The source currency key /// @param destinationCurrencyKey The destination currency key /// @return feeRate The exchange fee rate /// @return tooVolatile The exchange dynamic fee rate and if rates are too volatile function _feeRateForExchange( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) internal view returns (uint256 feeRate, bool tooVolatile) { // Get the exchange fee rate as per the source currencyKey and destination currencyKey uint256 baseRate = getExchangeFeeRate(sourceCurrencyKey).add(getExchangeFeeRate(destinationCurrencyKey)); uint256 dynamicFee; (dynamicFee, tooVolatile) = _dynamicFeeRateForExchange(sourceCurrencyKey, destinationCurrencyKey); return (baseRate.add(dynamicFee), tooVolatile); } /// @notice Calculate the exchange fee for a given source and destination currency key /// @param sourceCurrencyKey The source currency key /// @param destinationCurrencyKey The destination currency key /// @param roundIdForSrc The round id of the source currency. /// @param roundIdForDest The round id of the target currency. /// @return feeRate The exchange fee rate /// @return tooVolatile The exchange dynamic fee rate function _feeRateForExchangeAtRounds( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey, uint256 roundIdForSrc, uint256 roundIdForDest ) internal view returns (uint256 feeRate, bool tooVolatile) { // Get the exchange fee rate as per the source currencyKey and destination currencyKey uint256 baseRate = getExchangeFeeRate(sourceCurrencyKey).add(getExchangeFeeRate(destinationCurrencyKey)); uint256 dynamicFee; (dynamicFee, tooVolatile) = _dynamicFeeRateForExchangeAtRounds( sourceCurrencyKey, destinationCurrencyKey, roundIdForSrc, roundIdForDest ); return (baseRate.add(dynamicFee), tooVolatile); } function _dynamicFeeRateForExchange( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) internal view returns (uint256 dynamicFee, bool tooVolatile) { DynamicFeeConfig memory config = getExchangeDynamicFeeConfig(); (uint256 dynamicFeeDst, bool dstVolatile) = _dynamicFeeRateForCurrency(destinationCurrencyKey, config); (uint256 dynamicFeeSrc, bool srcVolatile) = _dynamicFeeRateForCurrency(sourceCurrencyKey, config); dynamicFee = dynamicFeeDst.add(dynamicFeeSrc); // cap to maxFee bool overMax = dynamicFee > config.maxFee; dynamicFee = overMax ? config.maxFee : dynamicFee; return (dynamicFee, overMax || dstVolatile || srcVolatile); } function _dynamicFeeRateForExchangeAtRounds( bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey, uint256 roundIdForSrc, uint256 roundIdForDest ) internal view returns (uint256 dynamicFee, bool tooVolatile) { DynamicFeeConfig memory config = getExchangeDynamicFeeConfig(); (uint256 dynamicFeeDst, bool dstVolatile) = _dynamicFeeRateForCurrencyRound( destinationCurrencyKey, roundIdForDest, config ); (uint256 dynamicFeeSrc, bool srcVolatile) = _dynamicFeeRateForCurrencyRound(sourceCurrencyKey, roundIdForSrc, config); dynamicFee = dynamicFeeDst.add(dynamicFeeSrc); // cap to maxFee bool overMax = dynamicFee > config.maxFee; dynamicFee = overMax ? config.maxFee : dynamicFee; return (dynamicFee, overMax || dstVolatile || srcVolatile); } /// @notice Get dynamic dynamicFee for a given currency key (SIP-184) /// @param currencyKey The given currency key /// @param config dynamic fee calculation configuration params /// @return dynamicFee The dynamic fee /// @return tooVolatile if it exceeds max dynamic fee set in config function _dynamicFeeRateForCurrency( bytes32 currencyKey, DynamicFeeConfig memory config ) internal view returns (uint256 dynamicFee, bool tooVolatile) { // no dynamic dynamicFee for sUSD or too few rounds if (currencyKey == sUSD || config.rounds <= 1) { return (0, false); } uint256 roundId = exchangeRates().getCurrentRoundId(currencyKey); return _dynamicFeeRateForCurrencyRound(currencyKey, roundId, config); } /// @notice Get dynamicFee for a given currency key (SIP-184) /// @param currencyKey The given currency key /// @param roundId The round id /// @param config dynamic fee calculation configuration params /// @return dynamicFee The dynamic fee /// @return tooVolatile if it exceeds max dynamic fee set in config function _dynamicFeeRateForCurrencyRound( bytes32 currencyKey, uint256 roundId, DynamicFeeConfig memory config ) internal view returns (uint256 dynamicFee, bool tooVolatile) { // no dynamic dynamicFee for sUSD or too few rounds if (currencyKey == sUSD || config.rounds <= 1) { return (0, false); } uint256[] memory prices; (prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, config.rounds, roundId); dynamicFee = _dynamicFeeCalculation(prices, config.threshold, config.weightDecay); // cap to maxFee bool overMax = dynamicFee > config.maxFee; dynamicFee = overMax ? config.maxFee : dynamicFee; return (dynamicFee, overMax); } /// @notice Calculate dynamic fee according to SIP-184 /// @param prices A list of prices from the current round to the previous rounds /// @param threshold A threshold to clip the price deviation ratop /// @param weightDecay A weight decay constant /// @return uint dynamic fee rate as decimal function _dynamicFeeCalculation( uint256[] memory prices, uint256 threshold, uint256 weightDecay ) internal pure returns (uint256) { // don't underflow if (prices.length == 0) { return 0; } uint256 dynamicFee = 0; // start with 0 // go backwards in price array for (uint256 i = prices.length - 1; i > 0; i--) { // apply decay from previous round (will be 0 for first round) dynamicFee = dynamicFee.multiplyDecimal(weightDecay); // calculate price deviation uint256 deviation = _thresholdedAbsDeviationRatio(prices[i - 1], prices[i], threshold); // add to total fee dynamicFee = dynamicFee.add(deviation); } return dynamicFee; } /// absolute price deviation ratio used by dynamic fee calculation /// deviationRatio = (abs(current - previous) / previous) - threshold /// if negative, zero is returned function _thresholdedAbsDeviationRatio( uint256 price, uint256 previousPrice, uint256 threshold ) internal pure returns (uint256) { if (previousPrice == 0) { return 0; // don't divide by zero } // abs difference between prices uint256 absDelta = price > previousPrice ? price - previousPrice : previousPrice - price; // relative to previous price uint256 deviationRatio = absDelta.divideDecimal(previousPrice); // only the positive difference from threshold return deviationRatio > threshold ? deviationRatio - threshold : 0; } function getAmountsForExchange( uint256 sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns (uint256 amountReceived, uint256 fee, uint256 exchangeFeeRate) { // The checks are added for consistency with the checks performed in _exchange() // The reverts (instead of no-op returns) are used order to prevent incorrect usage in calling contracts // (The no-op in _exchange() is in order to trigger system suspension if needed) // check synths active systemStatus().requireSynthActive(sourceCurrencyKey); systemStatus().requireSynthActive(destinationCurrencyKey); // check rates don't deviate above ciruit breaker allowed deviation (, bool srcInvalid) = exchangeCircuitBreaker().rateWithInvalid(sourceCurrencyKey); (, bool dstInvalid) = exchangeCircuitBreaker().rateWithInvalid(destinationCurrencyKey); require(!srcInvalid, "source synth rate invalid"); require(!dstInvalid, "destination synth rate invalid"); // check rates not stale or flagged _ensureCanExchange(sourceCurrencyKey, sourceAmount, destinationCurrencyKey); bool tooVolatile; (exchangeFeeRate, tooVolatile) = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey); // check rates volatility result require(!tooVolatile, "exchange rates too volatile"); (uint256 destinationAmount, , ) = exchangeRates().effectiveValueAndRates( sourceCurrencyKey, sourceAmount, destinationCurrencyKey ); amountReceived = _deductFeesFromAmount(destinationAmount, exchangeFeeRate); fee = destinationAmount.sub(amountReceived); } function _deductFeesFromAmount( uint256 destinationAmount, uint256 exchangeFeeRate ) internal pure returns (uint256 amountReceived) { amountReceived = destinationAmount.multiplyDecimal(SafeDecimalMath.unit().sub(exchangeFeeRate)); } function appendExchange( address account, bytes32 src, uint256 amount, bytes32 dest, uint256 amountReceived, uint256 exchangeFeeRate ) internal { IExchangeRates exRates = exchangeRates(); uint256 roundIdForSrc = exRates.getCurrentRoundId(src); uint256 roundIdForDest = exRates.getCurrentRoundId(dest); exchangeState().appendExchangeEntry( account, src, amount, dest, amountReceived, exchangeFeeRate, block.timestamp, roundIdForSrc, roundIdForDest ); emit ExchangeEntryAppended(account, src, amount, dest, amountReceived, exchangeFeeRate, roundIdForSrc, roundIdForDest); } function getRoundIdsAtPeriodEnd( IExchangeState.ExchangeEntry memory exchangeEntry ) internal view returns (uint256 srcRoundIdAtPeriodEnd, uint256 destRoundIdAtPeriodEnd) { IExchangeRates exRates = exchangeRates(); uint256 _waitingPeriodSecs = getWaitingPeriodSecs(); srcRoundIdAtPeriodEnd = exRates.getLastRoundIdBeforeElapsedSecs( exchangeEntry.src, exchangeEntry.roundIdForSrc, exchangeEntry.timestamp, _waitingPeriodSecs ); destRoundIdAtPeriodEnd = exRates.getLastRoundIdBeforeElapsedSecs( exchangeEntry.dest, exchangeEntry.roundIdForDest, exchangeEntry.timestamp, _waitingPeriodSecs ); } // ========== MODIFIERS ========== modifier onlyWrappedSynthrorSynth() { IWrappedSynthr _wrappedSynthr = wrappedSynthr(); require( msg.sender == address(_wrappedSynthr) || issuer().synthsByAddress(msg.sender) != bytes32(0), "Exchanger: Only wrappedSynthr or a synth contract can perform this action" ); _; } modifier onlySynthrBridge() { require(resolver.isBridge(msg.sender), "Exchanger: Only synthr bridge can call"); _; } // ========== EVENTS ========== event ExchangeEntryAppended( address indexed account, bytes32 src, uint256 amount, bytes32 dest, uint256 amountReceived, uint256 exchangeFeeRate, uint256 roundIdForSrc, uint256 roundIdForDest ); event ExchangeEntrySettled( address indexed from, bytes32 src, uint256 amount, bytes32 dest, uint256 reclaim, uint256 rebate, uint256 srcRoundIdAtPeriodEnd, uint256 destRoundIdAtPeriodEnd, uint256 exchangeTimestamp ); event SynthExchange( address indexed account, address indexed toAddress, bytes32 fromCurrencyKey, uint256 fromAmount, bytes32 toCurrencyKey, uint256 toAmount, uint256 fee, uint16 destChainId ); event TrackingSynthExchange( address indexed account, address indexed toAddress, bytes32 fromCurrencyKey, uint256 fromAmount, bytes32 toCurrencyKey, uint256 toAmount, uint256 fee, uint16 destChainId ); event ExchangeReclaim(address indexed account, bytes32 currencyKey, uint256 amount); event ExchangeRebate(address indexed account, bytes32 currencyKey, uint256 amount); event DestIssueForExchange(address indexed account, bytes32 currencyKey, uint256 amount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Internal references import "./AddressResolverLightChain.sol"; contract MixinResolver { AddressResolverLightChain public resolver; mapping(bytes32 => address) private addressCache; constructor(address _resolver) { resolver = AddressResolverLightChain(_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 (uint256 i = 0; i < first.length; i++) { combination[i] = first[i]; } for (uint256 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 virtual returns (bytes32[] memory addresses) {} function rebuildCache() public { bytes32[] memory requiredAddresses = resolverAddressesRequired(); // The resolver must call this function whenver it updates its state for (uint256 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 (uint256 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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./MixinResolver.sol"; // Internal references import "../interfaces/IFlexibleStorage.sol"; 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_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_AGGREGATOR_WARNING_FLAGS = "aggregatorWarningFlags"; 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 CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage"; struct DynamicFeeConfig { uint256 threshold; uint256 weightDecay; uint256 rounds; uint256 maxFee; } constructor(address _resolver) MixinResolver(_resolver) {} function resolverAddressesRequired() public view virtual override returns (bytes32[] memory addresses) { addresses = new bytes32[](1); addresses[0] = CONTRACT_FLEXIBLESTORAGE; } function flexibleStorage() internal view returns (IFlexibleStorage) { return IFlexibleStorage(requireAndGetAddress(CONTRACT_FLEXIBLESTORAGE)); } function getWaitingPeriodSecs() internal view returns (uint256) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_WAITING_PERIOD_SECS); } function getPriceDeviationThresholdFactor() internal view returns (uint256) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR); } function getRateStalePeriod() internal view returns (uint256) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_RATE_STALE_PERIOD); } /* ========== Exchange Related Fees ========== */ function getExchangeFeeRate(bytes32 currencyKey) internal view returns (uint256) { 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; uint256[] 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 getAggregatorWarningFlags() internal view returns (address) { return flexibleStorage().getAddressValue(SETTING_CONTRACT_NAME, SETTING_AGGREGATOR_WARNING_FLAGS); } function getAtomicMaxVolumePerBlock() internal view returns (uint256) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ATOMIC_MAX_VOLUME_PER_BLOCK); } function getAtomicTwapWindow() internal view returns (uint256) { 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 (uint256) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_ATOMIC_EXCHANGE_FEE_RATE, currencyKey)) ); } function getAtomicVolatilityConsiderationWindow(bytes32 currencyKey) internal view returns (uint256) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_ATOMIC_VOLATILITY_CONSIDERATION_WINDOW, currencyKey)) ); } function getAtomicVolatilityUpdateThreshold(bytes32 currencyKey) internal view returns (uint256) { 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)) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Owned { address public owner; address public nominatedOwner; constructor(address _owner) { 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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Libraries // import "openzeppelin-solidity-2.3.0/contracts/math/SafeMath.sol"; import "../externals/openzeppelin/SafeMath.sol"; library SafeDecimalMath { using SafeMath for uint256; /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint256 public constant UNIT = 10 ** uint256(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint256 public constant PRECISE_UNIT = 10 ** uint256(highPrecisionDecimals); uint256 private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10 ** uint256(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint256) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint256) { 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(uint256 x, uint256 y) internal pure returns (uint256) { /* 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(uint256 x, uint256 y, uint256 precisionUnit) private pure returns (uint256) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint256 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(uint256 x, uint256 y) internal pure returns (uint256) { 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(uint256 x, uint256 y) internal pure returns (uint256) { 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(uint256 x, uint256 y) internal pure returns (uint256) { /* 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(uint256 x, uint256 y, uint256 precisionUnit) private pure returns (uint256) { uint256 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(uint256 x, uint256 y) internal pure returns (uint256) { 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(uint256 x, uint256 y) internal pure returns (uint256) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint256 i) internal pure returns (uint256) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } /** * @dev Convert a high precision decimal to a standard decimal representation. */ function preciseDecimalToDecimal(uint256 i) internal pure returns (uint256) { uint256 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(uint256 a, uint256 b) internal pure returns (uint256) { return b >= a ? 0 : a - b; } /* ---------- Utilities ---------- */ /* * Absolute value of the input, returned as a signed number. */ function signedAbs(int256 x) internal pure returns (int256) { return x < 0 ? -x : x; } /* * Absolute value of the input, returned as an unsigned number. */ function abs(int256 x) internal pure returns (uint256) { return uint256(signedAbs(x)); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": { "contracts/lightChains/SafeDecimalMath.sol": { "SafeDecimalMath": "0xa1e534c7ae316eae135b89a76c7335e78fb1681e" } } }
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_resolver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"bytes32","name":"fromCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"toCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"destChainId","type":"uint16"}],"name":"AtomicSynthExchange","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":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DestIssueForExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"src","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"dest","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundIdForSrc","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"roundIdForDest","type":"uint256"}],"name":"ExchangeEntryAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"bytes32","name":"src","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"dest","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"reclaim","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rebate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"srcRoundIdAtPeriodEnd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destRoundIdAtPeriodEnd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeTimestamp","type":"uint256"}],"name":"ExchangeEntrySettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExchangeRebate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExchangeReclaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"bytes32","name":"fromCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"toCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"destChainId","type":"uint16"}],"name":"SynthExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"bytes32","name":"fromCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"toCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"destChainId","type":"uint16"}],"name":"TrackingSynthExchange","type":"event"},{"inputs":[],"name":"CONTRACT_NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"refunded","type":"uint256"}],"name":"calculateAmountAfterSettlement","outputs":[{"internalType":"uint256","name":"amountAfterSettlement","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"dynamicFeeRateForExchange","outputs":[{"internalType":"uint256","name":"feeRate","type":"uint256"},{"internalType":"bool","name":"tooVolatile","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fromAccount","type":"address"},{"internalType":"address","name":"destAccount","type":"address"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"reclaimed","type":"uint256"},{"internalType":"uint256","name":"refunded","type":"uint256"},{"internalType":"uint16","name":"destChainId","type":"uint16"},{"internalType":"bool","name":"erc20Payment","type":"bool"}],"internalType":"struct IExchanger.ExchangeArgs","name":"args","type":"tuple"},{"internalType":"bytes32","name":"bridgeName","type":"bytes32"}],"name":"exchange","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minAmount","type":"uint256"},{"components":[{"internalType":"address","name":"fromAccount","type":"address"},{"internalType":"address","name":"destAccount","type":"address"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"reclaimed","type":"uint256"},{"internalType":"uint256","name":"refunded","type":"uint256"},{"internalType":"uint16","name":"destChainId","type":"uint16"},{"internalType":"bool","name":"erc20Payment","type":"bool"}],"internalType":"struct IExchanger.ExchangeArgs","name":"args","type":"tuple"},{"internalType":"bytes32","name":"bridgeName","type":"bytes32"}],"name":"exchangeAtomically","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"feeRateForExchange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"getAmountsForAtomicExchange","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"getAmountsForExchange","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"exchangeFeeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bytes32","name":"_sourceKey","type":"bytes32"},{"internalType":"uint256","name":"_sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"_destKey","type":"bytes32"},{"internalType":"bytes32","name":"_bridgeName","type":"bytes32"},{"internalType":"uint16","name":"_destChainId","type":"uint16"}],"name":"getSendExchangeGasFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"isSynthRateInvalid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastAtomicVolume","outputs":[{"internalType":"uint64","name":"time","type":"uint64"},{"internalType":"uint192","name":"volume","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"maxSecsLeftInWaitingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebuildCache","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolverLightChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"settle","outputs":[{"internalType":"uint256","name":"reclaimed","type":"uint256"},{"internalType":"uint256","name":"refunded","type":"uint256"},{"internalType":"uint256","name":"numEntriesSettled","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"settlementOwing","outputs":[{"internalType":"uint256","name":"reclaimAmount","type":"uint256"},{"internalType":"uint256","name":"rebateAmount","type":"uint256"},{"internalType":"uint256","name":"numEntries","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"suspendSynthWithInvalidRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes32","name":"destinationKey","type":"bytes32"},{"internalType":"uint256","name":"destinationAmount","type":"uint256"}],"name":"updateDestinationForExchange","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620053fe380380620053fe833981016040819052620000349162000135565b81818080836001600160a01b038116620000945760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015260640160405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150600280546001600160a01b0319166001600160a01b0392909216919091179055506200016d9350505050565b80516001600160a01b03811681146200013057600080fd5b919050565b600080604083850312156200014957600080fd5b620001548362000118565b9150620001646020840162000118565b90509250929050565b615281806200017d6000396000f3fe60806040526004361061014b5760003560e01c806357af302c116100b65780638da5cb5b1161006f5780638da5cb5b146103bc5780638e52049c146103dc57806397935a3d14610437578063c39def0b1461044a578063dc703e731461047f578063f450aa341461049f57600080fd5b806357af302c14610310578063614d08f81461033057806364b6aef814610350578063741853601461037057806379ba509714610385578063899ffef41461039a57600080fd5b806319d5c6651161010857806319d5c665146102305780631a5c60951461026b5780631b16802c1461028b5780632af64bd3146102ab5780634c268fc8146102d057806353a47bb7146102f057600080fd5b806304f3bcec14610150578063059c29ec1461018d5780630b9e31c9146101bb5780630be5396a146101dd57806314ef073a146101f05780631627540c14610210575b600080fd5b34801561015c57600080fd5b50600254610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019957600080fd5b506101ad6101a83660046148df565b6104bf565b604051908152602001610184565b3480156101c757600080fd5b506101db6101d636600461490b565b61055c565b005b6101ad6101eb36600461493d565b61068c565b3480156101fc57600080fd5b506101db61020b366004614975565b6107e6565b34801561021c57600080fd5b506101db61022b3660046149aa565b610a37565b34801561023c57600080fd5b5061025061024b3660046148df565b610a93565b60408051938452602084019290925290820152606001610184565b34801561027757600080fd5b506101ad6102863660046149c7565b610ab1565b34801561029757600080fd5b506102506102a63660046148df565b610b01565b3480156102b757600080fd5b506102c0610b82565b6040519015158152602001610184565b3480156102dc57600080fd5b506101ad6102eb3660046149e9565b610ca2565b3480156102fc57600080fd5b50600154610170906001600160a01b031681565b34801561031c57600080fd5b506102c061032b36600461490b565b610dcf565b34801561033c57600080fd5b506101ad6822bc31b430b733b2b960b91b81565b34801561035c57600080fd5b506101ad61036b366004614a36565b610e5e565b34801561037c57600080fd5b506101db610f6d565b34801561039157600080fd5b506101db6110fd565b3480156103a657600080fd5b506103af6111e7565b6040516101849190614acb565b3480156103c857600080fd5b50600054610170906001600160a01b031681565b3480156103e857600080fd5b5060045461040f9067ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610184565b6101ad610445366004614ade565b61134c565b34801561045657600080fd5b5061046a6104653660046149c7565b611425565b60408051928352901515602083015201610184565b34801561048b57600080fd5b5061025061049a366004614b0b565b61143e565b3480156104ab57600080fd5b506102506104ba366004614b0b565b611461565b60006105536104cc611803565b604051631e280db960e31b81526001600160a01b03868116600483015260248201869052919091169063f1406dc89060440160206040518083038186803b15801561051657600080fd5b505afa15801561052a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054e9190614b37565b611823565b90505b92915050565b61056461186f565b6001600160a01b031663086dabd16040518163ffffffff1660e01b815260040160006040518083038186803b15801561059c57600080fd5b505afa1580156105b0573d6000803e3d6000fd5b5050505060006105be611889565b6001600160a01b031663a47af19e836040518263ffffffff1660e01b81526004016105eb91815260200190565b6040805180830381600087803b15801561060457600080fd5b505af1158015610618573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063c9190614b5e565b915050806106885760405162461bcd60e51b815260206004820152601460248201527314de5b9d1a081c1c9a58d9481a5cc81d985b1a5960621b60448201526064015b60405180910390fd5b5050565b6000806106976118ad565b9050336001600160a01b0382161480610731575060006106b56118c8565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f9060240160206040518083038186803b1580156106f657600080fd5b505afa15801561070a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072e9190614b37565b14155b61074d5760405162461bcd60e51b815260040161067f90614b8e565b61076561075f36869003860186614c48565b846118dc565b509150848210156107de5760405162461bcd60e51b815260206004820152603a60248201527f54686520616d6f756e742072656365697665642069732062656c6f772074686560448201527f206d696e696d756d20616d6f756e74207370656369666965642e000000000000606482015260840161067f565b509392505050565b600254604051633933006760e11b81523360048201526001600160a01b039091169063726600ce9060240160206040518083038186803b15801561082957600080fd5b505afa15801561083d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108619190614cf2565b6108bc5760405162461bcd60e51b815260206004820152602660248201527f45786368616e6765723a204f6e6c792073796e746872206272696467652063616044820152651b8818d85b1b60d21b606482015260840161067f565b816109005760405162461bcd60e51b81526020600482015260146024820152733232b9ba1035b2bc903234b23713ba1039b2ba1760611b604482015260640161067f565b600061090a6118c8565b6001600160a01b03166332608039846040518263ffffffff1660e01b815260040161093791815260200190565b60206040518083038186803b15801561094f57600080fd5b505afa158015610963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109879190614d0f565b60405163219e412d60e21b81526001600160a01b038681166004830152602482018590529192509082169063867904b490604401600060405180830381600087803b1580156109d557600080fd5b505af11580156109e9573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03881693507f6aef294c17150fbb566095411a70428ebfaac62db39b78dd3a83afc9456c78b692500160405180910390a250505050565b610a3f611df0565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b6000806000610aa28585611e64565b50919790965090945092505050565b6000806000610ac08585612204565b9150915080156107de5760405162461bcd60e51b815260206004820152600c60248201526b746f6f20766f6c6174696c6560a01b604482015260640161067f565b6000806000610b0e61186f565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b8152600401610b3b91815260200190565b60006040518083038186803b158015610b5357600080fd5b505afa158015610b67573d6000803e3d6000fd5b50505050610b75858561224b565b9250925092509250925092565b600080610b8d6111e7565b905060005b8151811015610c99576000828281518110610baf57610baf614d2c565b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b8152600481018390529193506001600160a01b039081169216906321f8a7219060240160206040518083038186803b158015610c1457600080fd5b505afa158015610c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4c9190614d0f565b6001600160a01b0316141580610c7757506000818152600360205260409020546001600160a01b0316155b15610c86576000935050505090565b5080610c9181614d58565b915050610b92565b50600191505090565b816000610cad6118c8565b6001600160a01b03166332608039866040518263ffffffff1660e01b8152600401610cda91815260200190565b60206040518083038186803b158015610cf257600080fd5b505afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a9190614d0f565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a082319060240160206040518083038186803b158015610d6d57600080fd5b505afa158015610d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da59190614b37565b90508215610dba57610db7828461250f565b91505b80821115610dc6578091505b50949350505050565b600080610dda611889565b6001600160a01b031663cb1ec317846040518263ffffffff1660e01b8152600401610e0791815260200190565b604080518083038186803b158015610e1e57600080fd5b505afa158015610e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e569190614b5e565b949350505050565b6000806000610e6e87898861256e565b50506040805160608f901b6bffffffffffffffffffffffff191660208201528151601481830301815260348201909252949650929450600093610ec5936005935091508c908c908c90899089908d90605401614dc0565b6040516020818303038152906040529050610edf86612642565b6001600160a01b0316632bb821bd826005886040518463ffffffff1660e01b8152600401610f0f93929190614e15565b60206040518083038186803b158015610f2757600080fd5b505afa158015610f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5f9190614b37565b9a9950505050505050505050565b6000610f776111e7565b905060005b8151811015610688576000828281518110610f9957610f99614d2c565b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d01838460405160200161100791907f5265736f6c766572206d697373696e67207461726765743a20000000000000008152601981019190915260390190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611033929190614e43565b60206040518083038186803b15801561104b57600080fd5b505afa15801561105f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110839190614d0f565b60008381526003602090815260409182902080546001600160a01b0319166001600160a01b0385169081179091558251868152918201529192507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68910160405180910390a1505080806110f590614d58565b915050610f7c565b6001546001600160a01b031633146111755760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b606482015260840161067f565b600054600154604080516001600160a01b0393841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b606060006111f36126be565b60408051600680825260e08201909252919250600091906020820160c0803683370190505090506b53797374656d53746174757360a01b8160008151811061123d5761123d614d2c565b6020026020010181815250506c45786368616e6765537461746560981b8160018151811061126d5761126d614d2c565b6020026020010181815250506c45786368616e6765526174657360981b8160028151811061129d5761129d614d2c565b6020026020010181815250506c2bb930b83832b229bcb73a343960991b816003815181106112cd576112cd614d2c565b6020026020010181815250506524b9b9bab2b960d11b816004815181106112f6576112f6614d2c565b6020026020010181815250507522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b8160058151811061132f5761132f614d2c565b6020026020010181815250506113458282612715565b9250505090565b6000806113576118ad565b9050336001600160a01b03821614806113f1575060006113756118c8565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f9060240160206040518083038186803b1580156113b657600080fd5b505afa1580156113ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ee9190614b37565b14155b61140d5760405162461bcd60e51b815260040161067f90614b8e565b610dc661141f36869003860186614c48565b84612827565b6000806114328484612cf0565b915091505b9250929050565b600080600061144e86868661256e565b50939a9299509097509095505050505050565b600080600061146e61186f565b6001600160a01b03166342a28e21866040518263ffffffff1660e01b815260040161149b91815260200190565b60006040518083038186803b1580156114b357600080fd5b505afa1580156114c7573d6000803e3d6000fd5b505050506114d361186f565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b815260040161150091815260200190565b60006040518083038186803b15801561151857600080fd5b505afa15801561152c573d6000803e3d6000fd5b50505050600061153a611889565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b815260040161156791815260200190565b604080518083038186803b15801561157e57600080fd5b505afa158015611592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b69190614b5e565b91505060006115c3611889565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b81526004016115f091815260200190565b604080518083038186803b15801561160757600080fd5b505afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163f9190614b5e565b91505081156116905760405162461bcd60e51b815260206004820152601960248201527f736f757263652073796e7468207261746520696e76616c696400000000000000604482015260640161067f565b80156116de5760405162461bcd60e51b815260206004820152601e60248201527f64657374696e6174696f6e2073796e7468207261746520696e76616c69640000604482015260640161067f565b6116e9878988612d6c565b60006116f58888612204565b909450905080156117485760405162461bcd60e51b815260206004820152601b60248201527f65786368616e676520726174657320746f6f20766f6c6174696c650000000000604482015260640161067f565b6000611752612ee1565b60405163414a80b560e11b8152600481018b9052602481018c9052604481018a90526001600160a01b039190911690638295016a9060640160606040518083038186803b1580156117a257600080fd5b505afa1580156117b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117da9190614e5c565b505090506117e88186612efc565b96506117f48188612f88565b95505050505093509350939050565b600061181e6c45786368616e6765537461746560981b612fe6565b905090565b60008061182e61305b565b90508215806118465750611842838261250f565b4210155b156118545750600092915050565b61186842611862858461250f565b90612f88565b9392505050565b600061181e6b53797374656d53746174757360a01b612fe6565b600061181e7522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b612fe6565b600061181e6c2bb930b83832b229bcb73a343960991b612fe6565b600061181e6524b9b9bab2b960d11b612fe6565b60008060008490506118fb816040015182608001518360600151612d6c565b611903612ee1565b6001600160a01b0316638661cc7b82604001516040518263ffffffff1660e01b815260040161193491815260200190565b60206040518083038186803b15801561194c57600080fd5b505afa158015611960573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119849190614cf2565b156119d15760405162461bcd60e51b815260206004820152601c60248201527f5372632073796e74682076616c756520697320766f6c6174696c652e00000000604482015260640161067f565b6119d9612ee1565b6001600160a01b0316638661cc7b82606001516040518263ffffffff1660e01b8152600401611a0a91815260200190565b60206040518083038186803b158015611a2257600080fd5b505afa158015611a36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5a9190614cf2565b15611aa75760405162461bcd60e51b815260206004820152601d60248201527f446573742073796e74682076616c756520697320766f6c6174696c652e000000604482015260640161067f565b611abe81608001518260000151836040015161310a565b61010084015260e083015260808201819052611ae1576000809250925050611437565b600080600080611afe85608001518660400151876060015161256e565b60a08b0186905260c08b0185905260408b015160608c0151969d50949b5092985090965094509250611b2f91613143565b15611b4557600080965096505050505050611437565b611b4d611889565b6001600160a01b03166378cb51cb84611b668a8a61250f565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160206040518083038186803b158015611ba257600080fd5b505afa158015611bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bda9190614cf2565b15611c275760405162461bcd60e51b815260206004820152601d60248201527f41746f6d6963207261746520646576696174657320746f6f206d756368000000604482015260640161067f565b6000631cd554d160e21b86604001511415611c4757506080890151611c9e565b631cd554d160e21b86606001511415611c61575082611c9e565b600080611c7e8c608001518960400151631cd554d160e21b61256e565b5050505091509150611c99818361250f90919063ffffffff16565b925050505b611ca781613285565b611cb1868a613331565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a606001518d8c60c001518d6101200151604051611d4296959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fa15ae7ed6a9ceafa6788f8020c73234a073e5fd311aca9b3250c93d374c07785886040015189608001518a606001518d8c60c001518d6101200151604051611ddb96959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a35050505050509250929050565b6000546001600160a01b03163314611e625760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b606482015260840161067f565b565b60008060006060611e73611803565b60405163b44e975360e01b81526001600160a01b03888116600483015260248201889052919091169063b44e97539060440160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef59190614b37565b915060008267ffffffffffffffff811115611f1257611f12614bfd565b604051908082528060200260200182016040528015611f9157816020015b611f7e60405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611f305790505b50905060005b838110156121f8576000806000611faf8b8b866136db565b9050600080611fbd83613810565b915091506000611fcb612ee1565b84516020860151604080880151905162d9ccd960e71b815260048101939093526024830191909152604482015260648101859052608481018490526001600160a01b039190911690636ce66c809060a40160606040518083038186803b15801561203457600080fd5b505afa158015612048573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206c9190614e5c565b505090506000612080828660800151612efc565b9050600061208c611889565b6001600160a01b03166378cb51cb8760600151846040518363ffffffff1660e01b81526004016120c6929190918252602082015260400190565b60206040518083038186803b1580156120de57600080fd5b505afa1580156120f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121169190614cf2565b90508061217657818660600151111561214b5760608601516121389083612f88565b97506121448e8961250f565b9d50612176565b8560600151821115612176576060860151612167908390612f88565b96506121738d8861250f565b9c505b6040518061010001604052808760000151815260200187602001518152602001876040015181526020018981526020018881526020018681526020018581526020018760a001518152508a8a815181106121d2576121d2614d2c565b6020026020010181905250505050505050505080806121f090614d58565b915050611f97565b50905092959194509250565b60008060006122246122158561396d565b61221e8761396d565b9061250f565b905060006122328686612cf0565b93509050612240828261250f565b935050509250929050565b600080600061225a85856104bf565b156122b35760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f7420736574746c6520647572696e672077616974696e67207065726044820152621a5bd960ea1b606482015260840161067f565b6000806000806122c38989611e64565b9350935093509350828411156122ef576122dd8484612f88565b96506122ea898989613a51565b61230e565b8383111561230e576123018385612f88565b955061230e898988613b84565b60005b815181101561249457896001600160a01b03167f8e3ad1f68bec55de3b6fa12ae2674a2a683a17c918a4cbf5157ac5d9ddc6e94083838151811061235757612357614d2c565b60200260200101516000015184848151811061237557612375614d2c565b60200260200101516020015185858151811061239357612393614d2c565b6020026020010151604001518686815181106123b1576123b1614d2c565b6020026020010151606001518787815181106123cf576123cf614d2c565b6020026020010151608001518888815181106123ed576123ed614d2c565b602002602001015160a0015189898151811061240b5761240b614d2c565b602002602001015160c001518a8a8151811061242957612429614d2c565b602002602001015160e0015160405161247a989796959493929190978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405180910390a28061248c81614d58565b915050612311565b508194506124a0611803565b604051636869eb1560e11b81526001600160a01b038b81166004830152602482018b9052919091169063d0d3d62a90604401600060405180830381600087803b1580156124ec57600080fd5b505af1158015612500573d6000803e3d6000fd5b50505050505050509250925092565b60008061251c8385614e8a565b9050838110156105535760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640161067f565b6000806000806000806000612581612ee1565b604051622a943760e51b8152600481018b9052602481018c9052604481018a90526001600160a01b03919091169063055286e09060640160806040518083038186803b1580156125d057600080fd5b505afa1580156125e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126089190614ea2565b91965094509250905061261b8989613cae565b94506126278186612efc565b96506126338188612f88565b95505093975093979195509350565b60025460405162c8ac9760e41b8152600481018390526000916001600160a01b031690630c8ac9709060240160206040518083038186803b15801561268657600080fd5b505afa15801561269a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105569190614d0f565b604080516001808252818301909252606091602080830190803683370190505090506e466c657869626c6553746f7261676560881b8160008151811061270657612706614d2c565b60200260200101818152505090565b6060815183516127259190614e8a565b67ffffffffffffffff81111561273d5761273d614bfd565b604051908082528060200260200182016040528015612766578160200160208202803683370190505b50905060005b83518110156127be5783818151811061278757612787614d2c565b60200260200101518282815181106127a1576127a1614d2c565b6020908102919091010152806127b681614d58565b91505061276c565b5060005b8251811015612820578281815181106127dd576127dd614d2c565b6020026020010151828286516127f39190614e8a565b8151811061280357612803614d2c565b60209081029190910101528061281881614d58565b9150506127c2565b5092915050565b600080600084608001511161286c5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b604482015260640161067f565b6128ac6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6128b4612ee1565b6001600160a01b0316637a018a1e86604001516040518263ffffffff1660e01b81526004016128e591815260200190565b60206040518083038186803b1580156128fd57600080fd5b505afa158015612911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129359190614b37565b60a0820152612942612ee1565b6001600160a01b0316637a018a1e86606001516040518263ffffffff1660e01b815260040161297391815260200190565b60206040518083038186803b15801561298b57600080fd5b505afa15801561299f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c39190614b37565b60c08201526080850151855160408701516129df92919061310a565b61010088015260e087015260808601819052612a02576000809250925050611437565b612a0a612ee1565b6040808701516080880151606089015160a086015160c0870151945162d9ccd960e71b8152600481019490945260248401929092526044830152606482015260848101919091526001600160a01b039190911690636ce66c809060a40160606040518083038186803b158015612a7f57600080fd5b505afa158015612a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab79190614e5c565b60208401528252604080830191909152850151606086015160a083015160c0840151612ae593929190613ce2565b612af785604001518660600151613143565b15612b09576000809250925050611437565b6000612b27866040015187606001518460a001518560c00151613e81565b606084019190915290508015612b4557600080935093505050611437565b612b5782604001518360600151612efc565b6040830151909450612b699085612f88565b60a0870185905260c087018190529250612b838686613331565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a60600151898c60c001518d6101200151604051612c1496959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fb5826da57a48b0e5d9160b88cdc4a9c303be1746b0619e42e51afe8fe353bbd9886040015189608001518a60600151898c60c001518d6101200151604051612cad96959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a36000612cbf61305b565b1115612ce757612ce78660200151876040015188608001518960600151888760600151613ec6565b50509250929050565b6000806000612cfd6140df565b9050600080612d0c8684614353565b91509150600080612d1d8986614353565b9092509050612d2c848361250f565b6060860151909750871180612d415787612d47565b85606001515b9750878180612d535750845b80612d5b5750825b975097505050505050509250929050565b60008211612daa5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b604482015260640161067f565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612ddf57612ddf614d2c565b6020026020010181815250508181600181518110612dff57612dff614d2c565b602002602001018181525050612e13612ee1565b6001600160a01b0316630a7d36d1826040518263ffffffff1660e01b8152600401612e3e9190614acb565b60206040518083038186803b158015612e5657600080fd5b505afa158015612e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e8e9190614cf2565b15612edb5760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e000000000000604482015260640161067f565b50505050565b600061181e6c45786368616e6765526174657360981b612fe6565b6000610553612f818373a1e534c7ae316eae135b89a76c7335e78fb1681e63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612f4957600080fd5b505af4158015612f5d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118629190614b37565b8490614420565b600082821115612fda5760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015260640161067f565b6000610e568385614ed8565b600081815260036020908152604080832054905170026b4b9b9b4b7339030b2323932b9b99d1607d1b92810192909252603182018490526001600160a01b03169081151590605101604051602081830303815290604052906128205760405162461bcd60e51b815260040161067f9190614eef565b6000613065614442565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527077616974696e67506572696f645365637360781b60248201526001600160a01b0391909116906323257c2b906044015b60206040518083038186803b1580156130d257600080fd5b505afa1580156130e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181e9190614b37565b60008060008061311a868661224b565b8996509194509250905080156131395761313686868985610ca2565b93505b5093509350939050565b6000631cd554d160e21b83146131dd5761315b611889565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b815260040161318891815260200190565b6040805180830381600087803b1580156131a157600080fd5b505af11580156131b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d99190614b5e565b9150505b631cd554d160e21b82146105565760006131f5611889565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b815260040161322291815260200190565b6040805180830381600087803b15801561323b57600080fd5b505af115801561324f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132739190614b5e565b915082905080610e5657509392505050565b60045460009067ffffffffffffffff1642146132a157816132be565b6004546132be90600160401b90046001600160c01b03168361250f565b90506132c861445f565b8111156133105760405162461bcd60e51b815260206004820152601660248201527514dd5c9c185cdcd959081d9bdb1d5b59481b1a5b5a5d60521b604482015260640161067f565b6001600160c01b0316600160401b0267ffffffffffffffff42161760045550565b6133396118c8565b6001600160a01b0316633260803983604001516040518263ffffffff1660e01b815260040161336a91815260200190565b60206040518083038186803b15801561338257600080fd5b505afa158015613396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ba9190614d0f565b82516080840151604051632770a7eb60e21b81526001600160a01b0392831660048201526024810191909152911690639dc29fac90604401600060405180830381600087803b15801561340c57600080fd5b505af1158015613420573d6000803e3d6000fd5b5050505081610120015161ffff16600014156135335760006134406118c8565b6001600160a01b0316633260803984606001516040518263ffffffff1660e01b815260040161347191815260200190565b60206040518083038186803b15801561348957600080fd5b505afa15801561349d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c19190614d0f565b602084015160a085015160405163219e412d60e21b81526001600160a01b039283166004820152602481019190915291925082169063867904b490604401600060405180830381600087803b15801561351957600080fd5b505af115801561352d573d6000803e3d6000fd5b50505050505b60008260c001511180156135525750631cd554d160e21b826060015114155b156135fc5761355f612ee1565b606083015160c0840151604051631952982b60e21b815260048101929092526024820152631cd554d160e21b60448201526001600160a01b03919091169063654a60ac9060640160206040518083038186803b1580156135be57600080fd5b505afa1580156135d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f69190614b37565b60c08301525b61360581612642565b82516040808501516060860151608087015160a088015160e08901516101008a015160c08b01516101208c01516101408d01519851632028bac560e21b81526001600160a01b039a8b166004820152602481019890985260448801969096526064870194909452608486019290925260a485015260c484015260e483015261ffff166101048201529015156101248201529116906380a2eb14903490610144016000604051808303818588803b1580156136be57600080fd5b505af11580156136d2573d6000803e3d6000fd5b50505050505050565b61372960405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008060008060008060008061373d611803565b604051630acc3f5b60e11b81526001600160a01b038e81166004830152602482018e9052604482018d905291909116906315987eb6906064016101006040518083038186803b15801561378f57600080fd5b505afa1580156137a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c79190614f02565b60408051610100810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201529c9b505050505050505050505050565b600080600061381d612ee1565b9050600061382961305b565b855160c087015160a088015160405163084f235160e11b8152600481019390935260248301919091526044820152606481018290529091506001600160a01b0383169063109e46a29060840160206040518083038186803b15801561388d57600080fd5b505afa1580156138a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138c59190614b37565b60408681015160e088015160a0890151925163084f235160e11b8152600481019290925260248201526044810191909152606481018390529094506001600160a01b0383169063109e46a29060840160206040518083038186803b15801561392c57600080fd5b505afa158015613940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139649190614b37565b92505050915091565b6000613977614442565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6e65786368616e67654665655261746560881b856040516020016139c5929190918252602082015260400190565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b8152600401613a01929190918252602082015260400190565b60206040518083038186803b158015613a1957600080fd5b505afa158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105569190614b37565b613a596118c8565b6001600160a01b03166332608039836040518263ffffffff1660e01b8152600401613a8691815260200190565b60206040518083038186803b158015613a9e57600080fd5b505afa158015613ab2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad69190614d0f565b604051632770a7eb60e21b81526001600160a01b038581166004830152602482018490529190911690639dc29fac90604401600060405180830381600087803b158015613b2257600080fd5b505af1158015613b36573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f491df6adf9cabe8ca514806effd6b6b6475572dc88fe4b8b58d0a20ecf45e1059250015b60405180910390a2505050565b613b8c6118c8565b6001600160a01b03166332608039836040518263ffffffff1660e01b8152600401613bb991815260200190565b60206040518083038186803b158015613bd157600080fd5b505afa158015613be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c099190614d0f565b60405163219e412d60e21b81526001600160a01b03858116600483015260248201849052919091169063867904b490604401600060405180830381600087803b158015613c5557600080fd5b505af1158015613c69573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f93751433c6897553c8950f14ccc193ccffb8f539f7421ffde9af83b9b7dae1a8925001613b77565b600080613cc6613cbd846144ce565b61221e866144ce565b90508061055357610e56613cd98461396d565b61221e8661396d565b6040805160028082526060820183526000926020830190803683370190505090508481600081518110613d1757613d17614d2c565b6020026020010181815250508381600181518110613d3757613d37614d2c565b6020908102919091010152604080516002808252606082019092526000918160200160208202803683370190505090508381600081518110613d7b57613d7b614d2c565b6020026020010181815250508281600181518110613d9b57613d9b614d2c565b602002602001018181525050613daf612ee1565b6001600160a01b031663d89ee86183836040518363ffffffff1660e01b8152600401613ddc929190614f5f565b60206040518083038186803b158015613df457600080fd5b505afa158015613e08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2c9190614cf2565b15613e795760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e000000000000604482015260640161067f565b505050505050565b6000806000613e9b613e928761396d565b61221e8961396d565b90506000613eab8888888861452c565b93509050613eb9828261250f565b9350505094509492505050565b6000613ed0612ee1565b604051633d00c50f60e11b8152600481018890529091506000906001600160a01b03831690637a018a1e9060240160206040518083038186803b158015613f1657600080fd5b505afa158015613f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f4e9190614b37565b604051633d00c50f60e11b8152600481018790529091506000906001600160a01b03841690637a018a1e9060240160206040518083038186803b158015613f9457600080fd5b505afa158015613fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fcc9190614b37565b9050613fd6611803565b604051630f2a761760e21b81526001600160a01b038b81166004830152602482018b9052604482018a9052606482018990526084820188905260a482018790524260c483015260e4820185905261010482018490529190911690633ca9d85c9061012401600060405180830381600087803b15801561405457600080fd5b505af1158015614068573d6000803e3d6000fd5b5050604080518b8152602081018b9052908101899052606081018890526080810187905260a0810185905260c081018490526001600160a01b038c1692507f62e40d554c7abcdd31074960d8347a2225daeb04d93bc748f049ba2ce9462398915060e00160405180910390a2505050505050505050565b61410a6040518060800160405280600081526020016000815260200160008152602001600081525090565b60408051600480825260a08201909252600091602082016080803683370190505090507f65786368616e676544796e616d69634665655468726573686f6c6400000000008160008151811061416157614161614d2c565b6020026020010181815250507f65786368616e676544796e616d69634665655765696768744465636179000000816001815181106141a1576141a1614d2c565b6020026020010181815250507f65786368616e676544796e616d6963466565526f756e64730000000000000000816002815181106141e1576141e1614d2c565b6020026020010181815250507465786368616e67654d617844796e616d696346656560581b8160038151811061421957614219614d2c565b602002602001018181525050600061422f614442565b6001600160a01b031663b67fa7ed6d53797374656d53657474696e677360901b846040518363ffffffff1660e01b815260040161426d929190614fb6565b60006040518083038186803b15801561428557600080fd5b505afa158015614299573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526142c1919081019061506a565b90506040518060800160405280826000815181106142e1576142e1614d2c565b602002602001015181526020018260018151811061430157614301614d2c565b602002602001015181526020018260028151811061432157614321614d2c565b602002602001015181526020018260038151811061434157614341614d2c565b60200260200101518152509250505090565b600080631cd554d160e21b84148061437057506001836040015111155b1561438057506000905080611437565b600061438a612ee1565b6001600160a01b0316637a018a1e866040518263ffffffff1660e01b81526004016143b791815260200190565b60206040518083038186803b1580156143cf57600080fd5b505afa1580156143e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144079190614b37565b90506144148582866145ac565b92509250509250929050565b600061442e6012600a615183565b61443884846146b6565b610553919061518f565b600061181e6e466c657869626c6553746f7261676560881b612fe6565b6000614469614442565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527f61746f6d69634d6178566f6c756d65506572426c6f636b00000000000000000060248201526001600160a01b0391909116906323257c2b906044016130ba565b60006144d8614442565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7461746f6d696345786368616e67654665655261746560581b856040516020016139c5929190918252602082015260400190565b60008060006145396140df565b90506000806145498887856145ac565b9150915060008061455b8b8a876145ac565b909250905061456a848361250f565b606086015190975087118061457f5787614585565b85606001515b97508781806145915750845b806145995750825b9750975050505050505094509492505050565b600080631cd554d160e21b8514806145c957506001836040015111155b156145d9575060009050806146ae565b60606145e3612ee1565b6040808601519051630ed7624560e41b8152600481018990526024810191909152604481018790526001600160a01b03919091169063ed7624509060640160006040518083038186803b15801561463957600080fd5b505afa15801561464d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261467591908101906151b1565b508091505061468d8185600001518660200151614735565b60608501519093508311806146a257836146a8565b84606001515b93509150505b935093915050565b6000826146c557506000610556565b60006146d18385615215565b9050826146de858361518f565b146105535760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b606482015260840161067f565b600083516000141561474957506000611868565b6000806001865161475a9190614ed8565b90505b8015610dc65761476d8285614420565b915060006147b887614780600185614ed8565b8151811061479057614790614d2c565b60200260200101518884815181106147aa576147aa614d2c565b6020026020010151886147da565b90506147c4838261250f565b92505080806147d290615234565b91505061475d565b6000826147e957506000611868565b6000838511614801576147fc8585614ed8565b61480b565b61480b8486614ed8565b90506000614819828661483d565b9050838111614829576000614833565b6148338482614ed8565b9695505050505050565b6000610553826148596148526012600a615183565b86906146b6565b9060008082116148ab5760405162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015260640161067f565b6000610e56838561518f565b6001600160a01b03811681146148cc57600080fd5b50565b80356148da816148b7565b919050565b600080604083850312156148f257600080fd5b82356148fd816148b7565b946020939093013593505050565b60006020828403121561491d57600080fd5b5035919050565b6000610160828403121561493757600080fd5b50919050565b60008060006101a0848603121561495357600080fd5b833592506149648560208601614924565b915061018084013590509250925092565b60008060006060848603121561498a57600080fd5b8335614995816148b7565b95602085013595506040909401359392505050565b6000602082840312156149bc57600080fd5b8135610553816148b7565b600080604083850312156149da57600080fd5b50508035926020909101359150565b600080600080608085870312156149ff57600080fd5b8435614a0a816148b7565b966020860135965060408601359560600135945092505050565b803561ffff811681146148da57600080fd5b60008060008060008060c08789031215614a4f57600080fd5b8635614a5a816148b7565b955060208701359450604087013593506060870135925060808701359150614a8460a08801614a24565b90509295509295509295565b600081518084526020808501945080840160005b83811015614ac057815187529582019590820190600101614aa4565b509495945050505050565b6020815260006105536020830184614a90565b6000806101808385031215614af257600080fd5b614afc8484614924565b94610160939093013593505050565b600080600060608486031215614b2057600080fd5b505081359360208301359350604090920135919050565b600060208284031215614b4957600080fd5b5051919050565b80151581146148cc57600080fd5b60008060408385031215614b7157600080fd5b825191506020830151614b8381614b50565b809150509250929050565b60208082526049908201527f45786368616e6765723a204f6e6c79207772617070656453796e746872206f7260408201527f20612073796e746820636f6e74726163742063616e20706572666f726d20746860608201526834b99030b1ba34b7b760b91b608082015260a00190565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614c3757614c37614bfd565b60405290565b80356148da81614b50565b60006101608284031215614c5b57600080fd5b614c63614c13565b614c6c836148cf565b8152614c7a602084016148cf565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e0820152610100808401358183015250610120614cd5818501614a24565b90820152610140614ce7848201614c3d565b908201529392505050565b600060208284031215614d0457600080fd5b815161055381614b50565b600060208284031215614d2157600080fd5b8151610553816148b7565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415614d6c57614d6c614d42565b5060010190565b6000815180845260005b81811015614d9957602081850181015186830182015201614d7d565b81811115614dab576000602083870101525b50601f01601f19169290920160200192915050565b600061010061ffff808c168452816020850152614ddf8285018c614d73565b604085019a909a5260608401989098525050608081019490945260a084019290925260c083015290911660e09091015292915050565b606081526000614e286060830186614d73565b61ffff94851660208401529290931660409091015292915050565b828152604060208201526000610e566040830184614d73565b600080600060608486031215614e7157600080fd5b8351925060208401519150604084015190509250925092565b60008219821115614e9d57614e9d614d42565b500190565b60008060008060808587031215614eb857600080fd5b505082516020840151604085015160609095015191969095509092509050565b600082821015614eea57614eea614d42565b500390565b6020815260006105536020830184614d73565b600080600080600080600080610100898b031215614f1f57600080fd5b505086516020880151604089015160608a015160808b015160a08c015160c08d015160e0909d0151959e949d50929b919a50985090965094509092509050565b604081526000614f726040830185614a90565b82810360208481019190915284518083528582019282019060005b81811015614fa957845183529383019391830191600101614f8d565b5090979650505050505050565b828152604060208201526000610e566040830184614a90565b600082601f830112614fe057600080fd5b8151602067ffffffffffffffff80831115614ffd57614ffd614bfd565b8260051b604051601f19603f8301168101818110848211171561502257615022614bfd565b60405293845285810183019383810192508785111561504057600080fd5b83870191505b8482101561505f57815183529183019190830190615046565b979650505050505050565b60006020828403121561507c57600080fd5b815167ffffffffffffffff81111561509357600080fd5b610e5684828501614fcf565b600181815b808511156150da5781600019048211156150c0576150c0614d42565b808516156150cd57918102915b93841c93908002906150a4565b509250929050565b6000826150f157506001610556565b816150fe57506000610556565b8160018114615114576002811461511e5761513a565b6001915050610556565b60ff84111561512f5761512f614d42565b50506001821b610556565b5060208310610133831016604e8410600b841016171561515d575081810a610556565b615167838361509f565b806000190482111561517b5761517b614d42565b029392505050565b600061055383836150e2565b6000826151ac57634e487b7160e01b600052601260045260246000fd5b500490565b600080604083850312156151c457600080fd5b825167ffffffffffffffff808211156151dc57600080fd5b6151e886838701614fcf565b935060208501519150808211156151fe57600080fd5b5061520b85828601614fcf565b9150509250929050565b600081600019048311821515161561522f5761522f614d42565b500290565b60008161524357615243614d42565b50600019019056fea26469706673582212205e97664359ef89e58d79a3d91702723d13c434c02e8ab4116bfea81d532c41cc64736f6c634300080900330000000000000000000000006f808ae3445a711ecaa4da5c8330b051541a4de000000000000000000000000014611eee8b9586d4af1f651682dca8e2c9daa234
Deployed Bytecode
0x60806040526004361061014b5760003560e01c806357af302c116100b65780638da5cb5b1161006f5780638da5cb5b146103bc5780638e52049c146103dc57806397935a3d14610437578063c39def0b1461044a578063dc703e731461047f578063f450aa341461049f57600080fd5b806357af302c14610310578063614d08f81461033057806364b6aef814610350578063741853601461037057806379ba509714610385578063899ffef41461039a57600080fd5b806319d5c6651161010857806319d5c665146102305780631a5c60951461026b5780631b16802c1461028b5780632af64bd3146102ab5780634c268fc8146102d057806353a47bb7146102f057600080fd5b806304f3bcec14610150578063059c29ec1461018d5780630b9e31c9146101bb5780630be5396a146101dd57806314ef073a146101f05780631627540c14610210575b600080fd5b34801561015c57600080fd5b50600254610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019957600080fd5b506101ad6101a83660046148df565b6104bf565b604051908152602001610184565b3480156101c757600080fd5b506101db6101d636600461490b565b61055c565b005b6101ad6101eb36600461493d565b61068c565b3480156101fc57600080fd5b506101db61020b366004614975565b6107e6565b34801561021c57600080fd5b506101db61022b3660046149aa565b610a37565b34801561023c57600080fd5b5061025061024b3660046148df565b610a93565b60408051938452602084019290925290820152606001610184565b34801561027757600080fd5b506101ad6102863660046149c7565b610ab1565b34801561029757600080fd5b506102506102a63660046148df565b610b01565b3480156102b757600080fd5b506102c0610b82565b6040519015158152602001610184565b3480156102dc57600080fd5b506101ad6102eb3660046149e9565b610ca2565b3480156102fc57600080fd5b50600154610170906001600160a01b031681565b34801561031c57600080fd5b506102c061032b36600461490b565b610dcf565b34801561033c57600080fd5b506101ad6822bc31b430b733b2b960b91b81565b34801561035c57600080fd5b506101ad61036b366004614a36565b610e5e565b34801561037c57600080fd5b506101db610f6d565b34801561039157600080fd5b506101db6110fd565b3480156103a657600080fd5b506103af6111e7565b6040516101849190614acb565b3480156103c857600080fd5b50600054610170906001600160a01b031681565b3480156103e857600080fd5b5060045461040f9067ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610184565b6101ad610445366004614ade565b61134c565b34801561045657600080fd5b5061046a6104653660046149c7565b611425565b60408051928352901515602083015201610184565b34801561048b57600080fd5b5061025061049a366004614b0b565b61143e565b3480156104ab57600080fd5b506102506104ba366004614b0b565b611461565b60006105536104cc611803565b604051631e280db960e31b81526001600160a01b03868116600483015260248201869052919091169063f1406dc89060440160206040518083038186803b15801561051657600080fd5b505afa15801561052a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054e9190614b37565b611823565b90505b92915050565b61056461186f565b6001600160a01b031663086dabd16040518163ffffffff1660e01b815260040160006040518083038186803b15801561059c57600080fd5b505afa1580156105b0573d6000803e3d6000fd5b5050505060006105be611889565b6001600160a01b031663a47af19e836040518263ffffffff1660e01b81526004016105eb91815260200190565b6040805180830381600087803b15801561060457600080fd5b505af1158015610618573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063c9190614b5e565b915050806106885760405162461bcd60e51b815260206004820152601460248201527314de5b9d1a081c1c9a58d9481a5cc81d985b1a5960621b60448201526064015b60405180910390fd5b5050565b6000806106976118ad565b9050336001600160a01b0382161480610731575060006106b56118c8565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f9060240160206040518083038186803b1580156106f657600080fd5b505afa15801561070a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072e9190614b37565b14155b61074d5760405162461bcd60e51b815260040161067f90614b8e565b61076561075f36869003860186614c48565b846118dc565b509150848210156107de5760405162461bcd60e51b815260206004820152603a60248201527f54686520616d6f756e742072656365697665642069732062656c6f772074686560448201527f206d696e696d756d20616d6f756e74207370656369666965642e000000000000606482015260840161067f565b509392505050565b600254604051633933006760e11b81523360048201526001600160a01b039091169063726600ce9060240160206040518083038186803b15801561082957600080fd5b505afa15801561083d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108619190614cf2565b6108bc5760405162461bcd60e51b815260206004820152602660248201527f45786368616e6765723a204f6e6c792073796e746872206272696467652063616044820152651b8818d85b1b60d21b606482015260840161067f565b816109005760405162461bcd60e51b81526020600482015260146024820152733232b9ba1035b2bc903234b23713ba1039b2ba1760611b604482015260640161067f565b600061090a6118c8565b6001600160a01b03166332608039846040518263ffffffff1660e01b815260040161093791815260200190565b60206040518083038186803b15801561094f57600080fd5b505afa158015610963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109879190614d0f565b60405163219e412d60e21b81526001600160a01b038681166004830152602482018590529192509082169063867904b490604401600060405180830381600087803b1580156109d557600080fd5b505af11580156109e9573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03881693507f6aef294c17150fbb566095411a70428ebfaac62db39b78dd3a83afc9456c78b692500160405180910390a250505050565b610a3f611df0565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b6000806000610aa28585611e64565b50919790965090945092505050565b6000806000610ac08585612204565b9150915080156107de5760405162461bcd60e51b815260206004820152600c60248201526b746f6f20766f6c6174696c6560a01b604482015260640161067f565b6000806000610b0e61186f565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b8152600401610b3b91815260200190565b60006040518083038186803b158015610b5357600080fd5b505afa158015610b67573d6000803e3d6000fd5b50505050610b75858561224b565b9250925092509250925092565b600080610b8d6111e7565b905060005b8151811015610c99576000828281518110610baf57610baf614d2c565b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b8152600481018390529193506001600160a01b039081169216906321f8a7219060240160206040518083038186803b158015610c1457600080fd5b505afa158015610c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4c9190614d0f565b6001600160a01b0316141580610c7757506000818152600360205260409020546001600160a01b0316155b15610c86576000935050505090565b5080610c9181614d58565b915050610b92565b50600191505090565b816000610cad6118c8565b6001600160a01b03166332608039866040518263ffffffff1660e01b8152600401610cda91815260200190565b60206040518083038186803b158015610cf257600080fd5b505afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a9190614d0f565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a082319060240160206040518083038186803b158015610d6d57600080fd5b505afa158015610d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da59190614b37565b90508215610dba57610db7828461250f565b91505b80821115610dc6578091505b50949350505050565b600080610dda611889565b6001600160a01b031663cb1ec317846040518263ffffffff1660e01b8152600401610e0791815260200190565b604080518083038186803b158015610e1e57600080fd5b505afa158015610e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e569190614b5e565b949350505050565b6000806000610e6e87898861256e565b50506040805160608f901b6bffffffffffffffffffffffff191660208201528151601481830301815260348201909252949650929450600093610ec5936005935091508c908c908c90899089908d90605401614dc0565b6040516020818303038152906040529050610edf86612642565b6001600160a01b0316632bb821bd826005886040518463ffffffff1660e01b8152600401610f0f93929190614e15565b60206040518083038186803b158015610f2757600080fd5b505afa158015610f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5f9190614b37565b9a9950505050505050505050565b6000610f776111e7565b905060005b8151811015610688576000828281518110610f9957610f99614d2c565b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d01838460405160200161100791907f5265736f6c766572206d697373696e67207461726765743a20000000000000008152601981019190915260390190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611033929190614e43565b60206040518083038186803b15801561104b57600080fd5b505afa15801561105f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110839190614d0f565b60008381526003602090815260409182902080546001600160a01b0319166001600160a01b0385169081179091558251868152918201529192507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68910160405180910390a1505080806110f590614d58565b915050610f7c565b6001546001600160a01b031633146111755760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b606482015260840161067f565b600054600154604080516001600160a01b0393841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b606060006111f36126be565b60408051600680825260e08201909252919250600091906020820160c0803683370190505090506b53797374656d53746174757360a01b8160008151811061123d5761123d614d2c565b6020026020010181815250506c45786368616e6765537461746560981b8160018151811061126d5761126d614d2c565b6020026020010181815250506c45786368616e6765526174657360981b8160028151811061129d5761129d614d2c565b6020026020010181815250506c2bb930b83832b229bcb73a343960991b816003815181106112cd576112cd614d2c565b6020026020010181815250506524b9b9bab2b960d11b816004815181106112f6576112f6614d2c565b6020026020010181815250507522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b8160058151811061132f5761132f614d2c565b6020026020010181815250506113458282612715565b9250505090565b6000806113576118ad565b9050336001600160a01b03821614806113f1575060006113756118c8565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f9060240160206040518083038186803b1580156113b657600080fd5b505afa1580156113ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ee9190614b37565b14155b61140d5760405162461bcd60e51b815260040161067f90614b8e565b610dc661141f36869003860186614c48565b84612827565b6000806114328484612cf0565b915091505b9250929050565b600080600061144e86868661256e565b50939a9299509097509095505050505050565b600080600061146e61186f565b6001600160a01b03166342a28e21866040518263ffffffff1660e01b815260040161149b91815260200190565b60006040518083038186803b1580156114b357600080fd5b505afa1580156114c7573d6000803e3d6000fd5b505050506114d361186f565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b815260040161150091815260200190565b60006040518083038186803b15801561151857600080fd5b505afa15801561152c573d6000803e3d6000fd5b50505050600061153a611889565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b815260040161156791815260200190565b604080518083038186803b15801561157e57600080fd5b505afa158015611592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b69190614b5e565b91505060006115c3611889565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b81526004016115f091815260200190565b604080518083038186803b15801561160757600080fd5b505afa15801561161b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163f9190614b5e565b91505081156116905760405162461bcd60e51b815260206004820152601960248201527f736f757263652073796e7468207261746520696e76616c696400000000000000604482015260640161067f565b80156116de5760405162461bcd60e51b815260206004820152601e60248201527f64657374696e6174696f6e2073796e7468207261746520696e76616c69640000604482015260640161067f565b6116e9878988612d6c565b60006116f58888612204565b909450905080156117485760405162461bcd60e51b815260206004820152601b60248201527f65786368616e676520726174657320746f6f20766f6c6174696c650000000000604482015260640161067f565b6000611752612ee1565b60405163414a80b560e11b8152600481018b9052602481018c9052604481018a90526001600160a01b039190911690638295016a9060640160606040518083038186803b1580156117a257600080fd5b505afa1580156117b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117da9190614e5c565b505090506117e88186612efc565b96506117f48188612f88565b95505050505093509350939050565b600061181e6c45786368616e6765537461746560981b612fe6565b905090565b60008061182e61305b565b90508215806118465750611842838261250f565b4210155b156118545750600092915050565b61186842611862858461250f565b90612f88565b9392505050565b600061181e6b53797374656d53746174757360a01b612fe6565b600061181e7522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b612fe6565b600061181e6c2bb930b83832b229bcb73a343960991b612fe6565b600061181e6524b9b9bab2b960d11b612fe6565b60008060008490506118fb816040015182608001518360600151612d6c565b611903612ee1565b6001600160a01b0316638661cc7b82604001516040518263ffffffff1660e01b815260040161193491815260200190565b60206040518083038186803b15801561194c57600080fd5b505afa158015611960573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119849190614cf2565b156119d15760405162461bcd60e51b815260206004820152601c60248201527f5372632073796e74682076616c756520697320766f6c6174696c652e00000000604482015260640161067f565b6119d9612ee1565b6001600160a01b0316638661cc7b82606001516040518263ffffffff1660e01b8152600401611a0a91815260200190565b60206040518083038186803b158015611a2257600080fd5b505afa158015611a36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5a9190614cf2565b15611aa75760405162461bcd60e51b815260206004820152601d60248201527f446573742073796e74682076616c756520697320766f6c6174696c652e000000604482015260640161067f565b611abe81608001518260000151836040015161310a565b61010084015260e083015260808201819052611ae1576000809250925050611437565b600080600080611afe85608001518660400151876060015161256e565b60a08b0186905260c08b0185905260408b015160608c0151969d50949b5092985090965094509250611b2f91613143565b15611b4557600080965096505050505050611437565b611b4d611889565b6001600160a01b03166378cb51cb84611b668a8a61250f565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160206040518083038186803b158015611ba257600080fd5b505afa158015611bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bda9190614cf2565b15611c275760405162461bcd60e51b815260206004820152601d60248201527f41746f6d6963207261746520646576696174657320746f6f206d756368000000604482015260640161067f565b6000631cd554d160e21b86604001511415611c4757506080890151611c9e565b631cd554d160e21b86606001511415611c61575082611c9e565b600080611c7e8c608001518960400151631cd554d160e21b61256e565b5050505091509150611c99818361250f90919063ffffffff16565b925050505b611ca781613285565b611cb1868a613331565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a606001518d8c60c001518d6101200151604051611d4296959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fa15ae7ed6a9ceafa6788f8020c73234a073e5fd311aca9b3250c93d374c07785886040015189608001518a606001518d8c60c001518d6101200151604051611ddb96959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a35050505050509250929050565b6000546001600160a01b03163314611e625760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b606482015260840161067f565b565b60008060006060611e73611803565b60405163b44e975360e01b81526001600160a01b03888116600483015260248201889052919091169063b44e97539060440160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef59190614b37565b915060008267ffffffffffffffff811115611f1257611f12614bfd565b604051908082528060200260200182016040528015611f9157816020015b611f7e60405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611f305790505b50905060005b838110156121f8576000806000611faf8b8b866136db565b9050600080611fbd83613810565b915091506000611fcb612ee1565b84516020860151604080880151905162d9ccd960e71b815260048101939093526024830191909152604482015260648101859052608481018490526001600160a01b039190911690636ce66c809060a40160606040518083038186803b15801561203457600080fd5b505afa158015612048573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206c9190614e5c565b505090506000612080828660800151612efc565b9050600061208c611889565b6001600160a01b03166378cb51cb8760600151846040518363ffffffff1660e01b81526004016120c6929190918252602082015260400190565b60206040518083038186803b1580156120de57600080fd5b505afa1580156120f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121169190614cf2565b90508061217657818660600151111561214b5760608601516121389083612f88565b97506121448e8961250f565b9d50612176565b8560600151821115612176576060860151612167908390612f88565b96506121738d8861250f565b9c505b6040518061010001604052808760000151815260200187602001518152602001876040015181526020018981526020018881526020018681526020018581526020018760a001518152508a8a815181106121d2576121d2614d2c565b6020026020010181905250505050505050505080806121f090614d58565b915050611f97565b50905092959194509250565b60008060006122246122158561396d565b61221e8761396d565b9061250f565b905060006122328686612cf0565b93509050612240828261250f565b935050509250929050565b600080600061225a85856104bf565b156122b35760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f7420736574746c6520647572696e672077616974696e67207065726044820152621a5bd960ea1b606482015260840161067f565b6000806000806122c38989611e64565b9350935093509350828411156122ef576122dd8484612f88565b96506122ea898989613a51565b61230e565b8383111561230e576123018385612f88565b955061230e898988613b84565b60005b815181101561249457896001600160a01b03167f8e3ad1f68bec55de3b6fa12ae2674a2a683a17c918a4cbf5157ac5d9ddc6e94083838151811061235757612357614d2c565b60200260200101516000015184848151811061237557612375614d2c565b60200260200101516020015185858151811061239357612393614d2c565b6020026020010151604001518686815181106123b1576123b1614d2c565b6020026020010151606001518787815181106123cf576123cf614d2c565b6020026020010151608001518888815181106123ed576123ed614d2c565b602002602001015160a0015189898151811061240b5761240b614d2c565b602002602001015160c001518a8a8151811061242957612429614d2c565b602002602001015160e0015160405161247a989796959493929190978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405180910390a28061248c81614d58565b915050612311565b508194506124a0611803565b604051636869eb1560e11b81526001600160a01b038b81166004830152602482018b9052919091169063d0d3d62a90604401600060405180830381600087803b1580156124ec57600080fd5b505af1158015612500573d6000803e3d6000fd5b50505050505050509250925092565b60008061251c8385614e8a565b9050838110156105535760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640161067f565b6000806000806000806000612581612ee1565b604051622a943760e51b8152600481018b9052602481018c9052604481018a90526001600160a01b03919091169063055286e09060640160806040518083038186803b1580156125d057600080fd5b505afa1580156125e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126089190614ea2565b91965094509250905061261b8989613cae565b94506126278186612efc565b96506126338188612f88565b95505093975093979195509350565b60025460405162c8ac9760e41b8152600481018390526000916001600160a01b031690630c8ac9709060240160206040518083038186803b15801561268657600080fd5b505afa15801561269a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105569190614d0f565b604080516001808252818301909252606091602080830190803683370190505090506e466c657869626c6553746f7261676560881b8160008151811061270657612706614d2c565b60200260200101818152505090565b6060815183516127259190614e8a565b67ffffffffffffffff81111561273d5761273d614bfd565b604051908082528060200260200182016040528015612766578160200160208202803683370190505b50905060005b83518110156127be5783818151811061278757612787614d2c565b60200260200101518282815181106127a1576127a1614d2c565b6020908102919091010152806127b681614d58565b91505061276c565b5060005b8251811015612820578281815181106127dd576127dd614d2c565b6020026020010151828286516127f39190614e8a565b8151811061280357612803614d2c565b60209081029190910101528061281881614d58565b9150506127c2565b5092915050565b600080600084608001511161286c5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b604482015260640161067f565b6128ac6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6128b4612ee1565b6001600160a01b0316637a018a1e86604001516040518263ffffffff1660e01b81526004016128e591815260200190565b60206040518083038186803b1580156128fd57600080fd5b505afa158015612911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129359190614b37565b60a0820152612942612ee1565b6001600160a01b0316637a018a1e86606001516040518263ffffffff1660e01b815260040161297391815260200190565b60206040518083038186803b15801561298b57600080fd5b505afa15801561299f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c39190614b37565b60c08201526080850151855160408701516129df92919061310a565b61010088015260e087015260808601819052612a02576000809250925050611437565b612a0a612ee1565b6040808701516080880151606089015160a086015160c0870151945162d9ccd960e71b8152600481019490945260248401929092526044830152606482015260848101919091526001600160a01b039190911690636ce66c809060a40160606040518083038186803b158015612a7f57600080fd5b505afa158015612a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab79190614e5c565b60208401528252604080830191909152850151606086015160a083015160c0840151612ae593929190613ce2565b612af785604001518660600151613143565b15612b09576000809250925050611437565b6000612b27866040015187606001518460a001518560c00151613e81565b606084019190915290508015612b4557600080935093505050611437565b612b5782604001518360600151612efc565b6040830151909450612b699085612f88565b60a0870185905260c087018190529250612b838686613331565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a60600151898c60c001518d6101200151604051612c1496959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fb5826da57a48b0e5d9160b88cdc4a9c303be1746b0619e42e51afe8fe353bbd9886040015189608001518a60600151898c60c001518d6101200151604051612cad96959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a36000612cbf61305b565b1115612ce757612ce78660200151876040015188608001518960600151888760600151613ec6565b50509250929050565b6000806000612cfd6140df565b9050600080612d0c8684614353565b91509150600080612d1d8986614353565b9092509050612d2c848361250f565b6060860151909750871180612d415787612d47565b85606001515b9750878180612d535750845b80612d5b5750825b975097505050505050509250929050565b60008211612daa5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b604482015260640161067f565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612ddf57612ddf614d2c565b6020026020010181815250508181600181518110612dff57612dff614d2c565b602002602001018181525050612e13612ee1565b6001600160a01b0316630a7d36d1826040518263ffffffff1660e01b8152600401612e3e9190614acb565b60206040518083038186803b158015612e5657600080fd5b505afa158015612e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e8e9190614cf2565b15612edb5760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e000000000000604482015260640161067f565b50505050565b600061181e6c45786368616e6765526174657360981b612fe6565b6000610553612f818373a1e534c7ae316eae135b89a76c7335e78fb1681e63907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015612f4957600080fd5b505af4158015612f5d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118629190614b37565b8490614420565b600082821115612fda5760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015260640161067f565b6000610e568385614ed8565b600081815260036020908152604080832054905170026b4b9b9b4b7339030b2323932b9b99d1607d1b92810192909252603182018490526001600160a01b03169081151590605101604051602081830303815290604052906128205760405162461bcd60e51b815260040161067f9190614eef565b6000613065614442565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527077616974696e67506572696f645365637360781b60248201526001600160a01b0391909116906323257c2b906044015b60206040518083038186803b1580156130d257600080fd5b505afa1580156130e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181e9190614b37565b60008060008061311a868661224b565b8996509194509250905080156131395761313686868985610ca2565b93505b5093509350939050565b6000631cd554d160e21b83146131dd5761315b611889565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b815260040161318891815260200190565b6040805180830381600087803b1580156131a157600080fd5b505af11580156131b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d99190614b5e565b9150505b631cd554d160e21b82146105565760006131f5611889565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b815260040161322291815260200190565b6040805180830381600087803b15801561323b57600080fd5b505af115801561324f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132739190614b5e565b915082905080610e5657509392505050565b60045460009067ffffffffffffffff1642146132a157816132be565b6004546132be90600160401b90046001600160c01b03168361250f565b90506132c861445f565b8111156133105760405162461bcd60e51b815260206004820152601660248201527514dd5c9c185cdcd959081d9bdb1d5b59481b1a5b5a5d60521b604482015260640161067f565b6001600160c01b0316600160401b0267ffffffffffffffff42161760045550565b6133396118c8565b6001600160a01b0316633260803983604001516040518263ffffffff1660e01b815260040161336a91815260200190565b60206040518083038186803b15801561338257600080fd5b505afa158015613396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ba9190614d0f565b82516080840151604051632770a7eb60e21b81526001600160a01b0392831660048201526024810191909152911690639dc29fac90604401600060405180830381600087803b15801561340c57600080fd5b505af1158015613420573d6000803e3d6000fd5b5050505081610120015161ffff16600014156135335760006134406118c8565b6001600160a01b0316633260803984606001516040518263ffffffff1660e01b815260040161347191815260200190565b60206040518083038186803b15801561348957600080fd5b505afa15801561349d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c19190614d0f565b602084015160a085015160405163219e412d60e21b81526001600160a01b039283166004820152602481019190915291925082169063867904b490604401600060405180830381600087803b15801561351957600080fd5b505af115801561352d573d6000803e3d6000fd5b50505050505b60008260c001511180156135525750631cd554d160e21b826060015114155b156135fc5761355f612ee1565b606083015160c0840151604051631952982b60e21b815260048101929092526024820152631cd554d160e21b60448201526001600160a01b03919091169063654a60ac9060640160206040518083038186803b1580156135be57600080fd5b505afa1580156135d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f69190614b37565b60c08301525b61360581612642565b82516040808501516060860151608087015160a088015160e08901516101008a015160c08b01516101208c01516101408d01519851632028bac560e21b81526001600160a01b039a8b166004820152602481019890985260448801969096526064870194909452608486019290925260a485015260c484015260e483015261ffff166101048201529015156101248201529116906380a2eb14903490610144016000604051808303818588803b1580156136be57600080fd5b505af11580156136d2573d6000803e3d6000fd5b50505050505050565b61372960405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008060008060008060008061373d611803565b604051630acc3f5b60e11b81526001600160a01b038e81166004830152602482018e9052604482018d905291909116906315987eb6906064016101006040518083038186803b15801561378f57600080fd5b505afa1580156137a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c79190614f02565b60408051610100810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201529c9b505050505050505050505050565b600080600061381d612ee1565b9050600061382961305b565b855160c087015160a088015160405163084f235160e11b8152600481019390935260248301919091526044820152606481018290529091506001600160a01b0383169063109e46a29060840160206040518083038186803b15801561388d57600080fd5b505afa1580156138a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138c59190614b37565b60408681015160e088015160a0890151925163084f235160e11b8152600481019290925260248201526044810191909152606481018390529094506001600160a01b0383169063109e46a29060840160206040518083038186803b15801561392c57600080fd5b505afa158015613940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139649190614b37565b92505050915091565b6000613977614442565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6e65786368616e67654665655261746560881b856040516020016139c5929190918252602082015260400190565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b8152600401613a01929190918252602082015260400190565b60206040518083038186803b158015613a1957600080fd5b505afa158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105569190614b37565b613a596118c8565b6001600160a01b03166332608039836040518263ffffffff1660e01b8152600401613a8691815260200190565b60206040518083038186803b158015613a9e57600080fd5b505afa158015613ab2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad69190614d0f565b604051632770a7eb60e21b81526001600160a01b038581166004830152602482018490529190911690639dc29fac90604401600060405180830381600087803b158015613b2257600080fd5b505af1158015613b36573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f491df6adf9cabe8ca514806effd6b6b6475572dc88fe4b8b58d0a20ecf45e1059250015b60405180910390a2505050565b613b8c6118c8565b6001600160a01b03166332608039836040518263ffffffff1660e01b8152600401613bb991815260200190565b60206040518083038186803b158015613bd157600080fd5b505afa158015613be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c099190614d0f565b60405163219e412d60e21b81526001600160a01b03858116600483015260248201849052919091169063867904b490604401600060405180830381600087803b158015613c5557600080fd5b505af1158015613c69573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f93751433c6897553c8950f14ccc193ccffb8f539f7421ffde9af83b9b7dae1a8925001613b77565b600080613cc6613cbd846144ce565b61221e866144ce565b90508061055357610e56613cd98461396d565b61221e8661396d565b6040805160028082526060820183526000926020830190803683370190505090508481600081518110613d1757613d17614d2c565b6020026020010181815250508381600181518110613d3757613d37614d2c565b6020908102919091010152604080516002808252606082019092526000918160200160208202803683370190505090508381600081518110613d7b57613d7b614d2c565b6020026020010181815250508281600181518110613d9b57613d9b614d2c565b602002602001018181525050613daf612ee1565b6001600160a01b031663d89ee86183836040518363ffffffff1660e01b8152600401613ddc929190614f5f565b60206040518083038186803b158015613df457600080fd5b505afa158015613e08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2c9190614cf2565b15613e795760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e000000000000604482015260640161067f565b505050505050565b6000806000613e9b613e928761396d565b61221e8961396d565b90506000613eab8888888861452c565b93509050613eb9828261250f565b9350505094509492505050565b6000613ed0612ee1565b604051633d00c50f60e11b8152600481018890529091506000906001600160a01b03831690637a018a1e9060240160206040518083038186803b158015613f1657600080fd5b505afa158015613f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f4e9190614b37565b604051633d00c50f60e11b8152600481018790529091506000906001600160a01b03841690637a018a1e9060240160206040518083038186803b158015613f9457600080fd5b505afa158015613fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fcc9190614b37565b9050613fd6611803565b604051630f2a761760e21b81526001600160a01b038b81166004830152602482018b9052604482018a9052606482018990526084820188905260a482018790524260c483015260e4820185905261010482018490529190911690633ca9d85c9061012401600060405180830381600087803b15801561405457600080fd5b505af1158015614068573d6000803e3d6000fd5b5050604080518b8152602081018b9052908101899052606081018890526080810187905260a0810185905260c081018490526001600160a01b038c1692507f62e40d554c7abcdd31074960d8347a2225daeb04d93bc748f049ba2ce9462398915060e00160405180910390a2505050505050505050565b61410a6040518060800160405280600081526020016000815260200160008152602001600081525090565b60408051600480825260a08201909252600091602082016080803683370190505090507f65786368616e676544796e616d69634665655468726573686f6c6400000000008160008151811061416157614161614d2c565b6020026020010181815250507f65786368616e676544796e616d69634665655765696768744465636179000000816001815181106141a1576141a1614d2c565b6020026020010181815250507f65786368616e676544796e616d6963466565526f756e64730000000000000000816002815181106141e1576141e1614d2c565b6020026020010181815250507465786368616e67654d617844796e616d696346656560581b8160038151811061421957614219614d2c565b602002602001018181525050600061422f614442565b6001600160a01b031663b67fa7ed6d53797374656d53657474696e677360901b846040518363ffffffff1660e01b815260040161426d929190614fb6565b60006040518083038186803b15801561428557600080fd5b505afa158015614299573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526142c1919081019061506a565b90506040518060800160405280826000815181106142e1576142e1614d2c565b602002602001015181526020018260018151811061430157614301614d2c565b602002602001015181526020018260028151811061432157614321614d2c565b602002602001015181526020018260038151811061434157614341614d2c565b60200260200101518152509250505090565b600080631cd554d160e21b84148061437057506001836040015111155b1561438057506000905080611437565b600061438a612ee1565b6001600160a01b0316637a018a1e866040518263ffffffff1660e01b81526004016143b791815260200190565b60206040518083038186803b1580156143cf57600080fd5b505afa1580156143e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144079190614b37565b90506144148582866145ac565b92509250509250929050565b600061442e6012600a615183565b61443884846146b6565b610553919061518f565b600061181e6e466c657869626c6553746f7261676560881b612fe6565b6000614469614442565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527f61746f6d69634d6178566f6c756d65506572426c6f636b00000000000000000060248201526001600160a01b0391909116906323257c2b906044016130ba565b60006144d8614442565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7461746f6d696345786368616e67654665655261746560581b856040516020016139c5929190918252602082015260400190565b60008060006145396140df565b90506000806145498887856145ac565b9150915060008061455b8b8a876145ac565b909250905061456a848361250f565b606086015190975087118061457f5787614585565b85606001515b97508781806145915750845b806145995750825b9750975050505050505094509492505050565b600080631cd554d160e21b8514806145c957506001836040015111155b156145d9575060009050806146ae565b60606145e3612ee1565b6040808601519051630ed7624560e41b8152600481018990526024810191909152604481018790526001600160a01b03919091169063ed7624509060640160006040518083038186803b15801561463957600080fd5b505afa15801561464d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261467591908101906151b1565b508091505061468d8185600001518660200151614735565b60608501519093508311806146a257836146a8565b84606001515b93509150505b935093915050565b6000826146c557506000610556565b60006146d18385615215565b9050826146de858361518f565b146105535760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b606482015260840161067f565b600083516000141561474957506000611868565b6000806001865161475a9190614ed8565b90505b8015610dc65761476d8285614420565b915060006147b887614780600185614ed8565b8151811061479057614790614d2c565b60200260200101518884815181106147aa576147aa614d2c565b6020026020010151886147da565b90506147c4838261250f565b92505080806147d290615234565b91505061475d565b6000826147e957506000611868565b6000838511614801576147fc8585614ed8565b61480b565b61480b8486614ed8565b90506000614819828661483d565b9050838111614829576000614833565b6148338482614ed8565b9695505050505050565b6000610553826148596148526012600a615183565b86906146b6565b9060008082116148ab5760405162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015260640161067f565b6000610e56838561518f565b6001600160a01b03811681146148cc57600080fd5b50565b80356148da816148b7565b919050565b600080604083850312156148f257600080fd5b82356148fd816148b7565b946020939093013593505050565b60006020828403121561491d57600080fd5b5035919050565b6000610160828403121561493757600080fd5b50919050565b60008060006101a0848603121561495357600080fd5b833592506149648560208601614924565b915061018084013590509250925092565b60008060006060848603121561498a57600080fd5b8335614995816148b7565b95602085013595506040909401359392505050565b6000602082840312156149bc57600080fd5b8135610553816148b7565b600080604083850312156149da57600080fd5b50508035926020909101359150565b600080600080608085870312156149ff57600080fd5b8435614a0a816148b7565b966020860135965060408601359560600135945092505050565b803561ffff811681146148da57600080fd5b60008060008060008060c08789031215614a4f57600080fd5b8635614a5a816148b7565b955060208701359450604087013593506060870135925060808701359150614a8460a08801614a24565b90509295509295509295565b600081518084526020808501945080840160005b83811015614ac057815187529582019590820190600101614aa4565b509495945050505050565b6020815260006105536020830184614a90565b6000806101808385031215614af257600080fd5b614afc8484614924565b94610160939093013593505050565b600080600060608486031215614b2057600080fd5b505081359360208301359350604090920135919050565b600060208284031215614b4957600080fd5b5051919050565b80151581146148cc57600080fd5b60008060408385031215614b7157600080fd5b825191506020830151614b8381614b50565b809150509250929050565b60208082526049908201527f45786368616e6765723a204f6e6c79207772617070656453796e746872206f7260408201527f20612073796e746820636f6e74726163742063616e20706572666f726d20746860608201526834b99030b1ba34b7b760b91b608082015260a00190565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614c3757614c37614bfd565b60405290565b80356148da81614b50565b60006101608284031215614c5b57600080fd5b614c63614c13565b614c6c836148cf565b8152614c7a602084016148cf565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e0820152610100808401358183015250610120614cd5818501614a24565b90820152610140614ce7848201614c3d565b908201529392505050565b600060208284031215614d0457600080fd5b815161055381614b50565b600060208284031215614d2157600080fd5b8151610553816148b7565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415614d6c57614d6c614d42565b5060010190565b6000815180845260005b81811015614d9957602081850181015186830182015201614d7d565b81811115614dab576000602083870101525b50601f01601f19169290920160200192915050565b600061010061ffff808c168452816020850152614ddf8285018c614d73565b604085019a909a5260608401989098525050608081019490945260a084019290925260c083015290911660e09091015292915050565b606081526000614e286060830186614d73565b61ffff94851660208401529290931660409091015292915050565b828152604060208201526000610e566040830184614d73565b600080600060608486031215614e7157600080fd5b8351925060208401519150604084015190509250925092565b60008219821115614e9d57614e9d614d42565b500190565b60008060008060808587031215614eb857600080fd5b505082516020840151604085015160609095015191969095509092509050565b600082821015614eea57614eea614d42565b500390565b6020815260006105536020830184614d73565b600080600080600080600080610100898b031215614f1f57600080fd5b505086516020880151604089015160608a015160808b015160a08c015160c08d015160e0909d0151959e949d50929b919a50985090965094509092509050565b604081526000614f726040830185614a90565b82810360208481019190915284518083528582019282019060005b81811015614fa957845183529383019391830191600101614f8d565b5090979650505050505050565b828152604060208201526000610e566040830184614a90565b600082601f830112614fe057600080fd5b8151602067ffffffffffffffff80831115614ffd57614ffd614bfd565b8260051b604051601f19603f8301168101818110848211171561502257615022614bfd565b60405293845285810183019383810192508785111561504057600080fd5b83870191505b8482101561505f57815183529183019190830190615046565b979650505050505050565b60006020828403121561507c57600080fd5b815167ffffffffffffffff81111561509357600080fd5b610e5684828501614fcf565b600181815b808511156150da5781600019048211156150c0576150c0614d42565b808516156150cd57918102915b93841c93908002906150a4565b509250929050565b6000826150f157506001610556565b816150fe57506000610556565b8160018114615114576002811461511e5761513a565b6001915050610556565b60ff84111561512f5761512f614d42565b50506001821b610556565b5060208310610133831016604e8410600b841016171561515d575081810a610556565b615167838361509f565b806000190482111561517b5761517b614d42565b029392505050565b600061055383836150e2565b6000826151ac57634e487b7160e01b600052601260045260246000fd5b500490565b600080604083850312156151c457600080fd5b825167ffffffffffffffff808211156151dc57600080fd5b6151e886838701614fcf565b935060208501519150808211156151fe57600080fd5b5061520b85828601614fcf565b9150509250929050565b600081600019048311821515161561522f5761522f614d42565b500290565b60008161524357615243614d42565b50600019019056fea26469706673582212205e97664359ef89e58d79a3d91702723d13c434c02e8ab4116bfea81d532c41cc64736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006f808ae3445a711ecaa4da5c8330b051541a4de000000000000000000000000014611eee8b9586d4af1f651682dca8e2c9daa234
-----Decoded View---------------
Arg [0] : _owner (address): 0x6F808aE3445A711ecAa4DA5c8330B051541A4dE0
Arg [1] : _resolver (address): 0x14611Eee8b9586d4AF1F651682dCA8e2c9DAA234
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000006f808ae3445a711ecaa4da5c8330b051541a4de0
Arg [1] : 00000000000000000000000014611eee8b9586d4af1f651682dca8e2c9daa234
Loading...
Loading
[ Download: CSV Export ]
[ 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.