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 | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Send Exchange | 7337042 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7337042 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7337032 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7337032 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336997 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336997 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336949 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336949 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336912 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336912 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336766 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336766 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336758 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336758 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336739 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336739 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336712 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336712 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336626 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336626 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336601 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336601 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336371 | 87 days ago | 0.00084179 ETH | ||||
Exchange Atomica... | 7336371 | 87 days ago | 0.00084179 ETH | ||||
Send Exchange | 7336369 | 87 days ago | 0.00084179 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 Source Code Verified (Exact Match)
Contract Name:
ExchangerWithFeeRecAlternativesLightChain
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity =0.8.24; // 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 ========== */ /** * @dev Returns the amounts received, fee, and exchange fee rate for an atomic exchange. * @param sourceAmount The amount of the source currency to be exchanged. * @param sourceCurrencyKey The currency key of the source currency. * @param destinationCurrencyKey The currency key of the destination currency. * @return amountReceived The amount of the destination currency received after the exchange. * @return fee The fee charged for the exchange. * @return exchangeFeeRate The exchange fee rate applied to the exchange. */ function getAmountsForAtomicExchange( uint256 sourceAmount, bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey ) external view returns (uint256 amountReceived, uint256 fee, uint256 exchangeFeeRate) { (amountReceived, fee, exchangeFeeRate, , , ) = _getAmountsForAtomicExchangeMinusFees( sourceAmount, sourceCurrencyKey, destinationCurrencyKey ); } /** * @dev Returns the gas fee for sending an exchange transaction. * @param _account The address of the account initiating the exchange. * @param _sourceKey The currency key of the source currency. * @param _sourceAmount The amount of the source currency to be exchanged. * @param _destKey The currency key of the destination currency. * @param _bridgeName The name of the bridge contract. * @param _destChainId The chain ID of the destination chain. * @return The gas fee for sending the exchange transaction. */ 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 ========== */ /** * @dev Allows the wrapped Synth or Synth to be exchanged atomically with a specified bridge. * @param minAmount The minimum amount of tokens to be received in the exchange. * @param args The exchange arguments containing the source and destination tokens, and the amount to be exchanged. * @param bridgeName The name of the bridge to be used for the exchange. * @return amountReceived The amount of tokens received in the exchange. */ 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.24; /** * @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.24; 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.24; 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.24; 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.24; 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.24; 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.24; 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.24; 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.24; 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.24; 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.24; 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.24; 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.24; 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.24; // 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.24; // 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.24; // 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.24; 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.24; 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.24; // 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 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": { "contracts/lightChains/SafeDecimalMath.sol": { "SafeDecimalMath": "0x06c1bad207a5ec045548238b8531087d8e038252" } } }
Contract ABI
API[{"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
60806040523480156200001157600080fd5b50604051620050ef380380620050ef833981016040819052620000349162000135565b81818080836001600160a01b038116620000945760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015260640160405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150600280546001600160a01b0319166001600160a01b0392909216919091179055506200016d9350505050565b80516001600160a01b03811681146200013057600080fd5b919050565b600080604083850312156200014957600080fd5b620001548362000118565b9150620001646020840162000118565b90509250929050565b614f72806200017d6000396000f3fe60806040526004361061014b5760003560e01c806357af302c116100b65780638da5cb5b1161006f5780638da5cb5b146103bc5780638e52049c146103dc57806397935a3d14610437578063c39def0b1461044a578063dc703e731461047f578063f450aa341461049f57600080fd5b806357af302c14610310578063614d08f81461033057806364b6aef814610350578063741853601461037057806379ba509714610385578063899ffef41461039a57600080fd5b806319d5c6651161010857806319d5c665146102305780631a5c60951461026b5780631b16802c1461028b5780632af64bd3146102ab5780634c268fc8146102d057806353a47bb7146102f057600080fd5b806304f3bcec14610150578063059c29ec1461018d5780630b9e31c9146101bb5780630be5396a146101dd57806314ef073a146101f05780631627540c14610210575b600080fd5b34801561015c57600080fd5b50600254610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019957600080fd5b506101ad6101a83660046145ff565b6104bf565b604051908152602001610184565b3480156101c757600080fd5b506101db6101d636600461462b565b61054d565b005b6101ad6101eb36600461465d565b61066e565b3480156101fc57600080fd5b506101db61020b366004614695565b6107b9565b34801561021c57600080fd5b506101db61022b3660046146ca565b6109ec565b34801561023c57600080fd5b5061025061024b3660046145ff565b610a48565b60408051938452602084019290925290820152606001610184565b34801561027757600080fd5b506101ad6102863660046146e7565b610a66565b34801561029757600080fd5b506102506102a63660046145ff565b610ab6565b3480156102b757600080fd5b506102c0610b37565b6040519015158152602001610184565b3480156102dc57600080fd5b506101ad6102eb366004614709565b610c3e565b3480156102fc57600080fd5b50600154610170906001600160a01b031681565b34801561031c57600080fd5b506102c061032b36600461462b565b610d4d565b34801561033c57600080fd5b506101ad6822bc31b430b733b2b960b91b81565b34801561035c57600080fd5b506101ad61036b366004614756565b610dcd565b34801561037c57600080fd5b506101db610ecd565b34801561039157600080fd5b506101db611043565b3480156103a657600080fd5b506103af61112d565b60405161018491906147ec565b3480156103c857600080fd5b50600054610170906001600160a01b031681565b3480156103e857600080fd5b5060045461040f9067ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610184565b6101ad6104453660046147ff565b611292565b34801561045657600080fd5b5061046a6104653660046146e7565b61135c565b60408051928352901515602083015201610184565b34801561048b57600080fd5b5061025061049a36600461482c565b611375565b3480156104ab57600080fd5b506102506104ba36600461482c565b611398565b60006105446104cc61170d565b604051631e280db960e31b81526001600160a01b03868116600483015260248201869052919091169063f1406dc890604401602060405180830381865afa15801561051b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053f9190614858565b61172d565b90505b92915050565b610555611779565b6001600160a01b031663086dabd16040518163ffffffff1660e01b815260040160006040518083038186803b15801561058d57600080fd5b505afa1580156105a1573d6000803e3d6000fd5b5050505060006105af611793565b6001600160a01b031663a47af19e836040518263ffffffff1660e01b81526004016105dc91815260200190565b60408051808303816000875af11580156105fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061e919061487f565b9150508061066a5760405162461bcd60e51b815260206004820152601460248201527314de5b9d1a081c1c9a58d9481a5cc81d985b1a5960621b60448201526064015b60405180910390fd5b5050565b6000806106796117b7565b9050336001600160a01b0382161480610704575060006106976117d2565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f90602401602060405180830381865afa1580156106dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107019190614858565b14155b6107205760405162461bcd60e51b8152600401610661906148af565b61073861073236869003860186614969565b846117e6565b509150848210156107b15760405162461bcd60e51b815260206004820152603a60248201527f54686520616d6f756e742072656365697665642069732062656c6f772074686560448201527f206d696e696d756d20616d6f756e74207370656369666965642e0000000000006064820152608401610661565b509392505050565b600254604051633933006760e11b81523360048201526001600160a01b039091169063726600ce90602401602060405180830381865afa158015610801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108259190614a13565b6108805760405162461bcd60e51b815260206004820152602660248201527f45786368616e6765723a204f6e6c792073796e746872206272696467652063616044820152651b8818d85b1b60d21b6064820152608401610661565b816108c45760405162461bcd60e51b81526020600482015260146024820152733232b9ba1035b2bc903234b23713ba1039b2ba1760611b6044820152606401610661565b60006108ce6117d2565b6001600160a01b03166332608039846040518263ffffffff1660e01b81526004016108fb91815260200190565b602060405180830381865afa158015610918573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093c9190614a30565b60405163219e412d60e21b81526001600160a01b038681166004830152602482018590529192509082169063867904b490604401600060405180830381600087803b15801561098a57600080fd5b505af115801561099e573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03881693507f6aef294c17150fbb566095411a70428ebfaac62db39b78dd3a83afc9456c78b692500160405180910390a250505050565b6109f4611cce565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b6000806000610a578585611d42565b50919790965090945092505050565b6000806000610a7585856120af565b9150915080156107b15760405162461bcd60e51b815260206004820152600c60248201526b746f6f20766f6c6174696c6560a01b6044820152606401610661565b6000806000610ac3611779565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b8152600401610af091815260200190565b60006040518083038186803b158015610b0857600080fd5b505afa158015610b1c573d6000803e3d6000fd5b50505050610b2a85856120f6565b9250925092509250925092565b600080610b4261112d565b905060005b8151811015610c35576000828281518110610b6457610b64614a4d565b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b8152600481018390529193506001600160a01b039081169216906321f8a72190602401602060405180830381865afa158015610bce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf29190614a30565b6001600160a01b0316141580610c1d57506000818152600360205260409020546001600160a01b0316155b15610c2c576000935050505090565b50600101610b47565b50600191505090565b816000610c496117d2565b6001600160a01b03166332608039866040518263ffffffff1660e01b8152600401610c7691815260200190565b602060405180830381865afa158015610c93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb79190614a30565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa158015610cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d239190614858565b90508215610d3857610d3582846123b0565b91505b80821115610d44578091505b50949350505050565b600080610d58611793565b6001600160a01b031663cb1ec317846040518263ffffffff1660e01b8152600401610d8591815260200190565b6040805180830381865afa158015610da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc5919061487f565b949350505050565b6000806000610ddd87898861240f565b50506040805160608f901b6bffffffffffffffffffffffff191660208201528151601481830301815260348201909252949650929450600093610e34936005935091508c908c908c90899089908d90605401614aa9565b6040516020818303038152906040529050610e4e866124d4565b6001600160a01b0316632bb821bd826005886040518463ffffffff1660e01b8152600401610e7e93929190614afe565b602060405180830381865afa158015610e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebf9190614858565b9a9950505050505050505050565b6000610ed761112d565b905060005b815181101561066a576000828281518110610ef957610ef9614a4d565b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610f6791907f5265736f6c766572206d697373696e67207461726765743a20000000000000008152601981019190915260390190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610f93929190614b2c565b602060405180830381865afa158015610fb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd49190614a30565b60008381526003602090815260409182902080546001600160a01b0319166001600160a01b0385169081179091558251868152918201529192507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68910160405180910390a15050600101610edc565b6001546001600160a01b031633146110bb5760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b6064820152608401610661565b600054600154604080516001600160a01b0393841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60606000611139612541565b60408051600680825260e08201909252919250600091906020820160c0803683370190505090506b53797374656d53746174757360a01b8160008151811061118357611183614a4d565b6020026020010181815250506c45786368616e6765537461746560981b816001815181106111b3576111b3614a4d565b6020026020010181815250506c45786368616e6765526174657360981b816002815181106111e3576111e3614a4d565b6020026020010181815250506c2bb930b83832b229bcb73a343960991b8160038151811061121357611213614a4d565b6020026020010181815250506524b9b9bab2b960d11b8160048151811061123c5761123c614a4d565b6020026020010181815250507522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b8160058151811061127557611275614a4d565b60200260200101818152505061128b8282612598565b9250505090565b60008061129d6117b7565b9050336001600160a01b0382161480611328575060006112bb6117d2565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f90602401602060405180830381865afa158015611301573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113259190614858565b14155b6113445760405162461bcd60e51b8152600401610661906148af565b610d4461135636869003860186614969565b84612696565b6000806113698484612b35565b915091505b9250929050565b600080600061138586868661240f565b50939a9299509097509095505050505050565b60008060006113a5611779565b6001600160a01b03166342a28e21866040518263ffffffff1660e01b81526004016113d291815260200190565b60006040518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b5050505061140a611779565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b815260040161143791815260200190565b60006040518083038186803b15801561144f57600080fd5b505afa158015611463573d6000803e3d6000fd5b505050506000611471611793565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b815260040161149e91815260200190565b6040805180830381865afa1580156114ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114de919061487f565b91505060006114eb611793565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b815260040161151891815260200190565b6040805180830381865afa158015611534573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611558919061487f565b91505081156115a95760405162461bcd60e51b815260206004820152601960248201527f736f757263652073796e7468207261746520696e76616c6964000000000000006044820152606401610661565b80156115f75760405162461bcd60e51b815260206004820152601e60248201527f64657374696e6174696f6e2073796e7468207261746520696e76616c696400006044820152606401610661565b611602878988612bb1565b600061160e88886120af565b909450905080156116615760405162461bcd60e51b815260206004820152601b60248201527f65786368616e676520726174657320746f6f20766f6c6174696c6500000000006044820152606401610661565b600061166b612d17565b60405163414a80b560e11b8152600481018b9052602481018c9052604481018a90526001600160a01b039190911690638295016a90606401606060405180830381865afa1580156116c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e49190614b45565b505090506116f28186612d32565b96506116fe8188612daf565b95505050505093509350939050565b60006117286c45786368616e6765537461746560981b612e0d565b905090565b600080611738612e82565b9050821580611750575061174c83826123b0565b4210155b1561175e5750600092915050565b6117724261176c85846123b0565b90612daf565b9392505050565b60006117286b53797374656d53746174757360a01b612e0d565b60006117287522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b612e0d565b60006117286c2bb930b83832b229bcb73a343960991b612e0d565b60006117286524b9b9bab2b960d11b612e0d565b6000806000849050611805816040015182608001518360600151612bb1565b61180d612d17565b6001600160a01b0316638661cc7b82604001516040518263ffffffff1660e01b815260040161183e91815260200190565b602060405180830381865afa15801561185b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187f9190614a13565b156118cc5760405162461bcd60e51b815260206004820152601c60248201527f5372632073796e74682076616c756520697320766f6c6174696c652e000000006044820152606401610661565b6118d4612d17565b6001600160a01b0316638661cc7b82606001516040518263ffffffff1660e01b815260040161190591815260200190565b602060405180830381865afa158015611922573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119469190614a13565b156119935760405162461bcd60e51b815260206004820152601d60248201527f446573742073796e74682076616c756520697320766f6c6174696c652e0000006044820152606401610661565b6119aa816080015182600001518360400151612f22565b61010084015260e0830152608082018190526000036119d057600080925092505061136e565b6000806000806119ed85608001518660400151876060015161240f565b60a08b0186905260c08b0185905260408b015160608c0151969d50949b5092985090965094509250611a1e91612f5b565b15611a345760008096509650505050505061136e565b611a3c611793565b6001600160a01b03166378cb51cb84611a558a8a6123b0565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401602060405180830381865afa158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190614a13565b15611b075760405162461bcd60e51b815260206004820152601d60248201527f41746f6d6963207261746520646576696174657320746f6f206d7563680000006044820152606401610661565b6000631cd554d160e21b866040015103611b2657506080890151611b7c565b631cd554d160e21b866060015103611b3f575082611b7c565b600080611b5c8c608001518960400151631cd554d160e21b61240f565b5050505091509150611b7781836123b090919063ffffffff16565b925050505b611b858161307f565b611b8f868a61312b565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a606001518d8c60c001518d6101200151604051611c2096959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fa15ae7ed6a9ceafa6788f8020c73234a073e5fd311aca9b3250c93d374c07785886040015189608001518a606001518d8c60c001518d6101200151604051611cb996959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a35050505050509250929050565b6000546001600160a01b03163314611d405760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b6064820152608401610661565b565b60008060006060611d5161170d565b60405163b44e975360e01b81526001600160a01b03888116600483015260248201889052919091169063b44e975390604401602060405180830381865afa158015611da0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc49190614858565b915060008267ffffffffffffffff811115611de157611de161491e565b604051908082528060200260200182016040528015611e6057816020015b611e4d60405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611dff5790505b50905060005b838110156120a3576000806000611e7e8b8b866134a7565b9050600080611e8c836135cd565b915091506000611e9a612d17565b84516020860151604080880151905162d9ccd960e71b815260048101939093526024830191909152604482015260648101859052608481018490526001600160a01b039190911690636ce66c809060a401606060405180830381865afa158015611f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2c9190614b45565b505090506000611f40828660800151612d32565b90506000611f4c611793565b6001600160a01b03166378cb51cb8760600151846040518363ffffffff1660e01b8152600401611f86929190918252602082015260400190565b602060405180830381865afa158015611fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc79190614a13565b905080612027578186606001511115611ffc576060860151611fe99083612daf565b9750611ff58e896123b0565b9d50612027565b8560600151821115612027576060860151612018908390612daf565b96506120248d886123b0565b9c505b6040518061010001604052808760000151815260200187602001518152602001876040015181526020018981526020018881526020018681526020018581526020018760a001518152508a8a8151811061208357612083614a4d565b602002602001018190525050505050505050508080600101915050611e66565b50905092959194509250565b60008060006120cf6120c08561370c565b6120c98761370c565b906123b0565b905060006120dd8686612b35565b935090506120eb82826123b0565b935050509250929050565b600080600061210585856104bf565b1561215e5760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f7420736574746c6520647572696e672077616974696e67207065726044820152621a5bd960ea1b6064820152608401610661565b60008060008061216e8989611d42565b93509350935093508284111561219a576121888484612daf565b96506121958989896137e1565b6121b9565b838311156121b9576121ac8385612daf565b95506121b9898988613905565b60005b815181101561233557896001600160a01b03167f8e3ad1f68bec55de3b6fa12ae2674a2a683a17c918a4cbf5157ac5d9ddc6e94083838151811061220257612202614a4d565b60200260200101516000015184848151811061222057612220614a4d565b60200260200101516020015185858151811061223e5761223e614a4d565b60200260200101516040015186868151811061225c5761225c614a4d565b60200260200101516060015187878151811061227a5761227a614a4d565b60200260200101516080015188888151811061229857612298614a4d565b602002602001015160a001518989815181106122b6576122b6614a4d565b602002602001015160c001518a8a815181106122d4576122d4614a4d565b602002602001015160e00151604051612325989796959493929190978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405180910390a26001016121bc565b5081945061234161170d565b604051636869eb1560e11b81526001600160a01b038b81166004830152602482018b9052919091169063d0d3d62a90604401600060405180830381600087803b15801561238d57600080fd5b505af11580156123a1573d6000803e3d6000fd5b50505050505050509250925092565b6000806123bd8385614b89565b9050838110156105445760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610661565b6000806000806000806000612422612d17565b604051622a943760e51b8152600481018b9052602481018c9052604481018a90526001600160a01b03919091169063055286e090606401608060405180830381865afa158015612476573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249a9190614b9c565b9196509450925090506124ad8989613a20565b94506124b98186612d32565b96506124c58188612daf565b95505093975093979195509350565b60025460405162c8ac9760e41b8152600481018390526000916001600160a01b031690630c8ac97090602401602060405180830381865afa15801561251d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105479190614a30565b604080516001808252818301909252606091602080830190803683370190505090506e466c657869626c6553746f7261676560881b8160008151811061258957612589614a4d565b60200260200101818152505090565b6060815183516125a89190614b89565b67ffffffffffffffff8111156125c0576125c061491e565b6040519080825280602002602001820160405280156125e9578160200160208202803683370190505b50905060005b83518110156126375783818151811061260a5761260a614a4d565b602002602001015182828151811061262457612624614a4d565b60209081029190910101526001016125ef565b5060005b825181101561268f5782818151811061265657612656614a4d565b60200260200101518282865161266c9190614b89565b8151811061267c5761267c614a4d565b602090810291909101015260010161263b565b5092915050565b60008060008460800151116126db5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610661565b61271b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b612723612d17565b6001600160a01b0316637a018a1e86604001516040518263ffffffff1660e01b815260040161275491815260200190565b602060405180830381865afa158015612771573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127959190614858565b60a08201526127a2612d17565b6001600160a01b0316637a018a1e86606001516040518263ffffffff1660e01b81526004016127d391815260200190565b602060405180830381865afa1580156127f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128149190614858565b60c0820152608085015185516040870151612830929190612f22565b61010088015260e08701526080860181905260000361285657600080925092505061136e565b61285e612d17565b6040808701516080880151606089015160a086015160c0870151945162d9ccd960e71b8152600481019490945260248401929092526044830152606482015260848101919091526001600160a01b039190911690636ce66c809060a401606060405180830381865afa1580156128d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fc9190614b45565b60208401528252604080830191909152850151606086015160a083015160c084015161292a93929190613a57565b61293c85604001518660600151612f5b565b1561294e57600080925092505061136e565b600061296c866040015187606001518460a001518560c00151613be7565b60608401919091529050801561298a5760008093509350505061136e565b61299c82604001518360600151612d32565b60408301519094506129ae9085612daf565b60a0870185905260c0870181905292506129c8868661312b565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a60600151898c60c001518d6101200151604051612a5996959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fb5826da57a48b0e5d9160b88cdc4a9c303be1746b0619e42e51afe8fe353bbd9886040015189608001518a60600151898c60c001518d6101200151604051612af296959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a36000612b04612e82565b1115612b2c57612b2c8660200151876040015188608001518960600151888760600151613c2c565b50509250929050565b6000806000612b42613e27565b9050600080612b51868461408c565b91509150600080612b62898661408c565b9092509050612b7184836123b0565b6060860151909750871180612b865787612b8c565b85606001515b9750878180612b985750845b80612ba05750825b975097505050505050509250929050565b60008211612bef5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610661565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612c2457612c24614a4d565b6020026020010181815250508181600181518110612c4457612c44614a4d565b602002602001018181525050612c58612d17565b6001600160a01b0316630a7d36d1826040518263ffffffff1660e01b8152600401612c8391906147ec565b602060405180830381865afa158015612ca0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc49190614a13565b15612d115760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e0000000000006044820152606401610661565b50505050565b60006117286c45786368616e6765526174657360981b612e0d565b6000610544612da8837306c1bad207a5ec045548238b8531087d8e03825263907af6c06040518163ffffffff1660e01b8152600401602060405180830381865af4158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176c9190614858565b849061414a565b600082821115612e015760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f7700006044820152606401610661565b6000610dc58385614bd2565b600081815260036020908152604080832054905170026b4b9b9b4b7339030b2323932b9b99d1607d1b92810192909252603182018490526001600160a01b031690811515906051016040516020818303038152906040529061268f5760405162461bcd60e51b81526004016106619190614be5565b6000612e8c61416c565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527077616974696e67506572696f645365637360781b60248201526001600160a01b0391909116906323257c2b906044015b602060405180830381865afa158015612efe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117289190614858565b600080600080612f3286866120f6565b899650919450925090508015612f5157612f4e86868985610c3e565b93505b5093509350939050565b6000631cd554d160e21b8314612fe657612f73611793565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b8152600401612fa091815260200190565b60408051808303816000875af1158015612fbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe2919061487f565b9150505b631cd554d160e21b8214610547576000612ffe611793565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b815260040161302b91815260200190565b60408051808303816000875af1158015613049573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061306d919061487f565b915082905080610dc557509392505050565b60045460009067ffffffffffffffff16421461309b57816130b8565b6004546130b890600160401b90046001600160c01b0316836123b0565b90506130c2614189565b81111561310a5760405162461bcd60e51b815260206004820152601660248201527514dd5c9c185cdcd959081d9bdb1d5b59481b1a5b5a5d60521b6044820152606401610661565b6001600160c01b0316600160401b0267ffffffffffffffff42161760045550565b6131336117d2565b6001600160a01b0316633260803983604001516040518263ffffffff1660e01b815260040161316491815260200190565b602060405180830381865afa158015613181573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a59190614a30565b82516080840151604051632770a7eb60e21b81526001600160a01b0392831660048201526024810191909152911690639dc29fac90604401600060405180830381600087803b1580156131f757600080fd5b505af115801561320b573d6000803e3d6000fd5b5050505081610120015161ffff1660000361330e57600061322a6117d2565b6001600160a01b0316633260803984606001516040518263ffffffff1660e01b815260040161325b91815260200190565b602060405180830381865afa158015613278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329c9190614a30565b602084015160a085015160405163219e412d60e21b81526001600160a01b039283166004820152602481019190915291925082169063867904b490604401600060405180830381600087803b1580156132f457600080fd5b505af1158015613308573d6000803e3d6000fd5b50505050505b60008260c0015111801561332d5750631cd554d160e21b826060015114155b156133c85761333a612d17565b606083015160c0840151604051631952982b60e21b815260048101929092526024820152631cd554d160e21b60448201526001600160a01b03919091169063654a60ac90606401602060405180830381865afa15801561339e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c29190614858565b60c08301525b6133d1816124d4565b82516040808501516060860151608087015160a088015160e08901516101008a015160c08b01516101208c01516101408d01519851632028bac560e21b81526001600160a01b039a8b166004820152602481019890985260448801969096526064870194909452608486019290925260a485015260c484015260e483015261ffff166101048201529015156101248201529116906380a2eb14903490610144016000604051808303818588803b15801561348a57600080fd5b505af115801561349e573d6000803e3d6000fd5b50505050505050565b6134f560405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008060008060008060008061350961170d565b604051630acc3f5b60e11b81526001600160a01b038e81166004830152602482018e9052604482018d905291909116906315987eb69060640161010060405180830381865afa158015613560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135849190614bf8565b60408051610100810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201529c9b505050505050505050505050565b60008060006135da612d17565b905060006135e6612e82565b855160c087015160a088015160405163084f235160e11b8152600481019390935260248301919091526044820152606481018290529091506001600160a01b0383169063109e46a290608401602060405180830381865afa15801561364f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136739190614858565b60408681015160e088015160a0890151925163084f235160e11b8152600481019290925260248201526044810191909152606481018390529094506001600160a01b0383169063109e46a290608401602060405180830381865afa1580156136df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137039190614858565b92505050915091565b600061371661416c565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6e65786368616e67654665655261746560881b85604051602001613764929190918252602082015260400190565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b81526004016137a0929190918252602082015260400190565b602060405180830381865afa1580156137bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105479190614858565b6137e96117d2565b6001600160a01b03166332608039836040518263ffffffff1660e01b815260040161381691815260200190565b602060405180830381865afa158015613833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138579190614a30565b604051632770a7eb60e21b81526001600160a01b038581166004830152602482018490529190911690639dc29fac90604401600060405180830381600087803b1580156138a357600080fd5b505af11580156138b7573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f491df6adf9cabe8ca514806effd6b6b6475572dc88fe4b8b58d0a20ecf45e1059250015b60405180910390a2505050565b61390d6117d2565b6001600160a01b03166332608039836040518263ffffffff1660e01b815260040161393a91815260200190565b602060405180830381865afa158015613957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061397b9190614a30565b60405163219e412d60e21b81526001600160a01b03858116600483015260248201849052919091169063867904b490604401600060405180830381600087803b1580156139c757600080fd5b505af11580156139db573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f93751433c6897553c8950f14ccc193ccffb8f539f7421ffde9af83b9b7dae1a89250016138f8565b600080613a38613a2f846141f8565b6120c9866141f8565b90508060000361054457610dc5613a4e8461370c565b6120c98661370c565b6040805160028082526060820183526000926020830190803683370190505090508481600081518110613a8c57613a8c614a4d565b6020026020010181815250508381600181518110613aac57613aac614a4d565b6020908102919091010152604080516002808252606082019092526000918160200160208202803683370190505090508381600081518110613af057613af0614a4d565b6020026020010181815250508281600181518110613b1057613b10614a4d565b602002602001018181525050613b24612d17565b6001600160a01b031663d89ee86183836040518363ffffffff1660e01b8152600401613b51929190614c55565b602060405180830381865afa158015613b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b929190614a13565b15613bdf5760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e0000000000006044820152606401610661565b505050505050565b6000806000613c01613bf88761370c565b6120c98961370c565b90506000613c1188888888614256565b93509050613c1f82826123b0565b9350505094509492505050565b6000613c36612d17565b604051633d00c50f60e11b8152600481018890529091506000906001600160a01b03831690637a018a1e90602401602060405180830381865afa158015613c81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ca59190614858565b604051633d00c50f60e11b8152600481018790529091506000906001600160a01b03841690637a018a1e90602401602060405180830381865afa158015613cf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d149190614858565b9050613d1e61170d565b604051630f2a761760e21b81526001600160a01b038b81166004830152602482018b9052604482018a9052606482018990526084820188905260a482018790524260c483015260e4820185905261010482018490529190911690633ca9d85c9061012401600060405180830381600087803b158015613d9c57600080fd5b505af1158015613db0573d6000803e3d6000fd5b5050604080518b8152602081018b9052908101899052606081018890526080810187905260a0810185905260c081018490526001600160a01b038c1692507f62e40d554c7abcdd31074960d8347a2225daeb04d93bc748f049ba2ce9462398915060e00160405180910390a2505050505050505050565b613e526040518060800160405280600081526020016000815260200160008152602001600081525090565b60408051600480825260a08201909252600091602082016080803683370190505090507f65786368616e676544796e616d69634665655468726573686f6c64000000000081600081518110613ea957613ea9614a4d565b6020026020010181815250507f65786368616e676544796e616d6963466565576569676874446563617900000081600181518110613ee957613ee9614a4d565b6020026020010181815250507f65786368616e676544796e616d6963466565526f756e6473000000000000000081600281518110613f2957613f29614a4d565b6020026020010181815250507465786368616e67654d617844796e616d696346656560581b81600381518110613f6157613f61614a4d565b6020026020010181815250506000613f7761416c565b6001600160a01b031663b67fa7ed6d53797374656d53657474696e677360901b846040518363ffffffff1660e01b8152600401613fb5929190614cac565b600060405180830381865afa158015613fd2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ffa9190810190614d63565b905060405180608001604052808260008151811061401a5761401a614a4d565b602002602001015181526020018260018151811061403a5761403a614a4d565b602002602001015181526020018260028151811061405a5761405a614a4d565b602002602001015181526020018260038151811061407a5761407a614a4d565b60200260200101518152509250505090565b600080631cd554d160e21b8414806140a957506001836040015111155b156140b95750600090508061136e565b60006140c3612d17565b6001600160a01b0316637a018a1e866040518263ffffffff1660e01b81526004016140f091815260200190565b602060405180830381865afa15801561410d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141319190614858565b905061413e8582866142d6565b92509250509250929050565b60006141586012600a614e7c565b61416284846143d1565b6105449190614e88565b60006117286e466c657869626c6553746f7261676560881b612e0d565b600061419361416c565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527f61746f6d69634d6178566f6c756d65506572426c6f636b00000000000000000060248201526001600160a01b0391909116906323257c2b90604401612ee1565b600061420261416c565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7461746f6d696345786368616e67654665655261746560581b85604051602001613764929190918252602082015260400190565b6000806000614263613e27565b90506000806142738887856142d6565b915091506000806142858b8a876142d6565b909250905061429484836123b0565b60608601519097508711806142a957876142af565b85606001515b97508781806142bb5750845b806142c35750825b9750975050505050505094509492505050565b600080631cd554d160e21b8514806142f357506001836040015111155b15614303575060009050806143c9565b606061430d612d17565b6040808601519051630ed7624560e41b8152600481018990526024810191909152604481018790526001600160a01b03919091169063ed76245090606401600060405180830381865afa158015614368573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526143909190810190614eaa565b50809150506143a88185600001518660200151614453565b60608501519093508311806143bd57836143c3565b84606001515b93509150505b935093915050565b6000826000036143e357506000610547565b60006143ef8385614f0e565b9050826143fc8583614e88565b146105445760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b6064820152608401610661565b6000835160000361446657506000611772565b600080600186516144779190614bd2565b90505b8015610d445761448a828561414a565b915060006144d58761449d600185614bd2565b815181106144ad576144ad614a4d565b60200260200101518884815181106144c7576144c7614a4d565b6020026020010151886144f7565b90506144e183826123b0565b92505080806144ef90614f25565b91505061447a565b60008260000361450957506000611772565b60008385116145215761451c8585614bd2565b61452b565b61452b8486614bd2565b90506000614539828661455d565b9050838111614549576000614553565b6145538482614bd2565b9695505050505050565b6000610544826145796145726012600a614e7c565b86906143d1565b9060008082116145cb5760405162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f0000000000006044820152606401610661565b6000610dc58385614e88565b6001600160a01b03811681146145ec57600080fd5b50565b80356145fa816145d7565b919050565b6000806040838503121561461257600080fd5b823561461d816145d7565b946020939093013593505050565b60006020828403121561463d57600080fd5b5035919050565b6000610160828403121561465757600080fd5b50919050565b60008060006101a0848603121561467357600080fd5b833592506146848560208601614644565b915061018084013590509250925092565b6000806000606084860312156146aa57600080fd5b83356146b5816145d7565b95602085013595506040909401359392505050565b6000602082840312156146dc57600080fd5b8135610544816145d7565b600080604083850312156146fa57600080fd5b50508035926020909101359150565b6000806000806080858703121561471f57600080fd5b843561472a816145d7565b966020860135965060408601359560600135945092505050565b803561ffff811681146145fa57600080fd5b60008060008060008060c0878903121561476f57600080fd5b863561477a816145d7565b9550602087013594506040870135935060608701359250608087013591506147a460a08801614744565b90509295509295509295565b60008151808452602080850194506020840160005b838110156147e1578151875295820195908201906001016147c5565b509495945050505050565b60208152600061054460208301846147b0565b600080610180838503121561481357600080fd5b61481d8484614644565b94610160939093013593505050565b60008060006060848603121561484157600080fd5b505081359360208301359350604090920135919050565b60006020828403121561486a57600080fd5b5051919050565b80151581146145ec57600080fd5b6000806040838503121561489257600080fd5b8251915060208301516148a481614871565b809150509250929050565b60208082526049908201527f45786368616e6765723a204f6e6c79207772617070656453796e746872206f7260408201527f20612073796e746820636f6e74726163742063616e20706572666f726d20746860608201526834b99030b1ba34b7b760b91b608082015260a00190565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff811182821017156149585761495861491e565b60405290565b80356145fa81614871565b6000610160828403121561497c57600080fd5b614984614934565b61498d836145ef565b815261499b602084016145ef565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206149f6818501614744565b90820152610140614a0884820161495e565b908201529392505050565b600060208284031215614a2557600080fd5b815161054481614871565b600060208284031215614a4257600080fd5b8151610544816145d7565b634e487b7160e01b600052603260045260246000fd5b6000815180845260005b81811015614a8957602081850181015186830182015201614a6d565b506000602082860101526020601f19601f83011685010191505092915050565b600061010061ffff808c168452816020850152614ac88285018c614a63565b604085019a909a5260608401989098525050608081019490945260a084019290925260c083015290911660e09091015292915050565b606081526000614b116060830186614a63565b61ffff94851660208401529290931660409091015292915050565b828152604060208201526000610dc56040830184614a63565b600080600060608486031215614b5a57600080fd5b8351925060208401519150604084015190509250925092565b634e487b7160e01b600052601160045260246000fd5b8082018082111561054757610547614b73565b60008060008060808587031215614bb257600080fd5b505082516020840151604085015160609095015191969095509092509050565b8181038181111561054757610547614b73565b6020815260006105446020830184614a63565b600080600080600080600080610100898b031215614c1557600080fd5b505086516020880151604089015160608a015160808b015160a08c015160c08d015160e0909d0151959e949d50929b919a50985090965094509092509050565b604081526000614c6860408301856147b0565b82810360208481019190915284518083528582019282019060005b81811015614c9f57845183529383019391830191600101614c83565b5090979650505050505050565b828152604060208201526000610dc560408301846147b0565b600082601f830112614cd657600080fd5b8151602067ffffffffffffffff80831115614cf357614cf361491e565b8260051b604051601f19603f83011681018181108482111715614d1857614d1861491e565b6040529384526020818701810194908101925087851115614d3857600080fd5b6020870191505b84821015614d5857815183529183019190830190614d3f565b979650505050505050565b600060208284031215614d7557600080fd5b815167ffffffffffffffff811115614d8c57600080fd5b610dc584828501614cc5565b600181815b80851115614dd3578160001904821115614db957614db9614b73565b80851615614dc657918102915b93841c9390800290614d9d565b509250929050565b600082614dea57506001610547565b81614df757506000610547565b8160018114614e0d5760028114614e1757614e33565b6001915050610547565b60ff841115614e2857614e28614b73565b50506001821b610547565b5060208310610133831016604e8410600b8410161715614e56575081810a610547565b614e608383614d98565b8060001904821115614e7457614e74614b73565b029392505050565b60006105448383614ddb565b600082614ea557634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215614ebd57600080fd5b825167ffffffffffffffff80821115614ed557600080fd5b614ee186838701614cc5565b93506020850151915080821115614ef757600080fd5b50614f0485828601614cc5565b9150509250929050565b808202811582820484141761054757610547614b73565b600081614f3457614f34614b73565b50600019019056fea26469706673582212207fe994478d6b73905bbc3168c0055d72301be88244b4564734008004f91e4af064736f6c634300081800330000000000000000000000006f808ae3445a711ecaa4da5c8330b051541a4de000000000000000000000000049a6e93768f0ba860c578da3b7b8de3b9b29f7ed
Deployed Bytecode
0x60806040526004361061014b5760003560e01c806357af302c116100b65780638da5cb5b1161006f5780638da5cb5b146103bc5780638e52049c146103dc57806397935a3d14610437578063c39def0b1461044a578063dc703e731461047f578063f450aa341461049f57600080fd5b806357af302c14610310578063614d08f81461033057806364b6aef814610350578063741853601461037057806379ba509714610385578063899ffef41461039a57600080fd5b806319d5c6651161010857806319d5c665146102305780631a5c60951461026b5780631b16802c1461028b5780632af64bd3146102ab5780634c268fc8146102d057806353a47bb7146102f057600080fd5b806304f3bcec14610150578063059c29ec1461018d5780630b9e31c9146101bb5780630be5396a146101dd57806314ef073a146101f05780631627540c14610210575b600080fd5b34801561015c57600080fd5b50600254610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019957600080fd5b506101ad6101a83660046145ff565b6104bf565b604051908152602001610184565b3480156101c757600080fd5b506101db6101d636600461462b565b61054d565b005b6101ad6101eb36600461465d565b61066e565b3480156101fc57600080fd5b506101db61020b366004614695565b6107b9565b34801561021c57600080fd5b506101db61022b3660046146ca565b6109ec565b34801561023c57600080fd5b5061025061024b3660046145ff565b610a48565b60408051938452602084019290925290820152606001610184565b34801561027757600080fd5b506101ad6102863660046146e7565b610a66565b34801561029757600080fd5b506102506102a63660046145ff565b610ab6565b3480156102b757600080fd5b506102c0610b37565b6040519015158152602001610184565b3480156102dc57600080fd5b506101ad6102eb366004614709565b610c3e565b3480156102fc57600080fd5b50600154610170906001600160a01b031681565b34801561031c57600080fd5b506102c061032b36600461462b565b610d4d565b34801561033c57600080fd5b506101ad6822bc31b430b733b2b960b91b81565b34801561035c57600080fd5b506101ad61036b366004614756565b610dcd565b34801561037c57600080fd5b506101db610ecd565b34801561039157600080fd5b506101db611043565b3480156103a657600080fd5b506103af61112d565b60405161018491906147ec565b3480156103c857600080fd5b50600054610170906001600160a01b031681565b3480156103e857600080fd5b5060045461040f9067ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610184565b6101ad6104453660046147ff565b611292565b34801561045657600080fd5b5061046a6104653660046146e7565b61135c565b60408051928352901515602083015201610184565b34801561048b57600080fd5b5061025061049a36600461482c565b611375565b3480156104ab57600080fd5b506102506104ba36600461482c565b611398565b60006105446104cc61170d565b604051631e280db960e31b81526001600160a01b03868116600483015260248201869052919091169063f1406dc890604401602060405180830381865afa15801561051b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053f9190614858565b61172d565b90505b92915050565b610555611779565b6001600160a01b031663086dabd16040518163ffffffff1660e01b815260040160006040518083038186803b15801561058d57600080fd5b505afa1580156105a1573d6000803e3d6000fd5b5050505060006105af611793565b6001600160a01b031663a47af19e836040518263ffffffff1660e01b81526004016105dc91815260200190565b60408051808303816000875af11580156105fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061e919061487f565b9150508061066a5760405162461bcd60e51b815260206004820152601460248201527314de5b9d1a081c1c9a58d9481a5cc81d985b1a5960621b60448201526064015b60405180910390fd5b5050565b6000806106796117b7565b9050336001600160a01b0382161480610704575060006106976117d2565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f90602401602060405180830381865afa1580156106dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107019190614858565b14155b6107205760405162461bcd60e51b8152600401610661906148af565b61073861073236869003860186614969565b846117e6565b509150848210156107b15760405162461bcd60e51b815260206004820152603a60248201527f54686520616d6f756e742072656365697665642069732062656c6f772074686560448201527f206d696e696d756d20616d6f756e74207370656369666965642e0000000000006064820152608401610661565b509392505050565b600254604051633933006760e11b81523360048201526001600160a01b039091169063726600ce90602401602060405180830381865afa158015610801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108259190614a13565b6108805760405162461bcd60e51b815260206004820152602660248201527f45786368616e6765723a204f6e6c792073796e746872206272696467652063616044820152651b8818d85b1b60d21b6064820152608401610661565b816108c45760405162461bcd60e51b81526020600482015260146024820152733232b9ba1035b2bc903234b23713ba1039b2ba1760611b6044820152606401610661565b60006108ce6117d2565b6001600160a01b03166332608039846040518263ffffffff1660e01b81526004016108fb91815260200190565b602060405180830381865afa158015610918573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093c9190614a30565b60405163219e412d60e21b81526001600160a01b038681166004830152602482018590529192509082169063867904b490604401600060405180830381600087803b15801561098a57600080fd5b505af115801561099e573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03881693507f6aef294c17150fbb566095411a70428ebfaac62db39b78dd3a83afc9456c78b692500160405180910390a250505050565b6109f4611cce565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b6000806000610a578585611d42565b50919790965090945092505050565b6000806000610a7585856120af565b9150915080156107b15760405162461bcd60e51b815260206004820152600c60248201526b746f6f20766f6c6174696c6560a01b6044820152606401610661565b6000806000610ac3611779565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b8152600401610af091815260200190565b60006040518083038186803b158015610b0857600080fd5b505afa158015610b1c573d6000803e3d6000fd5b50505050610b2a85856120f6565b9250925092509250925092565b600080610b4261112d565b905060005b8151811015610c35576000828281518110610b6457610b64614a4d565b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b8152600481018390529193506001600160a01b039081169216906321f8a72190602401602060405180830381865afa158015610bce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf29190614a30565b6001600160a01b0316141580610c1d57506000818152600360205260409020546001600160a01b0316155b15610c2c576000935050505090565b50600101610b47565b50600191505090565b816000610c496117d2565b6001600160a01b03166332608039866040518263ffffffff1660e01b8152600401610c7691815260200190565b602060405180830381865afa158015610c93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb79190614a30565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa158015610cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d239190614858565b90508215610d3857610d3582846123b0565b91505b80821115610d44578091505b50949350505050565b600080610d58611793565b6001600160a01b031663cb1ec317846040518263ffffffff1660e01b8152600401610d8591815260200190565b6040805180830381865afa158015610da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc5919061487f565b949350505050565b6000806000610ddd87898861240f565b50506040805160608f901b6bffffffffffffffffffffffff191660208201528151601481830301815260348201909252949650929450600093610e34936005935091508c908c908c90899089908d90605401614aa9565b6040516020818303038152906040529050610e4e866124d4565b6001600160a01b0316632bb821bd826005886040518463ffffffff1660e01b8152600401610e7e93929190614afe565b602060405180830381865afa158015610e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebf9190614858565b9a9950505050505050505050565b6000610ed761112d565b905060005b815181101561066a576000828281518110610ef957610ef9614a4d565b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610f6791907f5265736f6c766572206d697373696e67207461726765743a20000000000000008152601981019190915260390190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610f93929190614b2c565b602060405180830381865afa158015610fb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd49190614a30565b60008381526003602090815260409182902080546001600160a01b0319166001600160a01b0385169081179091558251868152918201529192507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68910160405180910390a15050600101610edc565b6001546001600160a01b031633146110bb5760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b6064820152608401610661565b600054600154604080516001600160a01b0393841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b60606000611139612541565b60408051600680825260e08201909252919250600091906020820160c0803683370190505090506b53797374656d53746174757360a01b8160008151811061118357611183614a4d565b6020026020010181815250506c45786368616e6765537461746560981b816001815181106111b3576111b3614a4d565b6020026020010181815250506c45786368616e6765526174657360981b816002815181106111e3576111e3614a4d565b6020026020010181815250506c2bb930b83832b229bcb73a343960991b8160038151811061121357611213614a4d565b6020026020010181815250506524b9b9bab2b960d11b8160048151811061123c5761123c614a4d565b6020026020010181815250507522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b8160058151811061127557611275614a4d565b60200260200101818152505061128b8282612598565b9250505090565b60008061129d6117b7565b9050336001600160a01b0382161480611328575060006112bb6117d2565b6040516316b2213f60e01b81523360048201526001600160a01b0391909116906316b2213f90602401602060405180830381865afa158015611301573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113259190614858565b14155b6113445760405162461bcd60e51b8152600401610661906148af565b610d4461135636869003860186614969565b84612696565b6000806113698484612b35565b915091505b9250929050565b600080600061138586868661240f565b50939a9299509097509095505050505050565b60008060006113a5611779565b6001600160a01b03166342a28e21866040518263ffffffff1660e01b81526004016113d291815260200190565b60006040518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b5050505061140a611779565b6001600160a01b03166342a28e21856040518263ffffffff1660e01b815260040161143791815260200190565b60006040518083038186803b15801561144f57600080fd5b505afa158015611463573d6000803e3d6000fd5b505050506000611471611793565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b815260040161149e91815260200190565b6040805180830381865afa1580156114ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114de919061487f565b91505060006114eb611793565b6001600160a01b031663cb1ec317876040518263ffffffff1660e01b815260040161151891815260200190565b6040805180830381865afa158015611534573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611558919061487f565b91505081156115a95760405162461bcd60e51b815260206004820152601960248201527f736f757263652073796e7468207261746520696e76616c6964000000000000006044820152606401610661565b80156115f75760405162461bcd60e51b815260206004820152601e60248201527f64657374696e6174696f6e2073796e7468207261746520696e76616c696400006044820152606401610661565b611602878988612bb1565b600061160e88886120af565b909450905080156116615760405162461bcd60e51b815260206004820152601b60248201527f65786368616e676520726174657320746f6f20766f6c6174696c6500000000006044820152606401610661565b600061166b612d17565b60405163414a80b560e11b8152600481018b9052602481018c9052604481018a90526001600160a01b039190911690638295016a90606401606060405180830381865afa1580156116c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e49190614b45565b505090506116f28186612d32565b96506116fe8188612daf565b95505050505093509350939050565b60006117286c45786368616e6765537461746560981b612e0d565b905090565b600080611738612e82565b9050821580611750575061174c83826123b0565b4210155b1561175e5750600092915050565b6117724261176c85846123b0565b90612daf565b9392505050565b60006117286b53797374656d53746174757360a01b612e0d565b60006117287522bc31b430b733b2a1b4b931bab4ba213932b0b5b2b960511b612e0d565b60006117286c2bb930b83832b229bcb73a343960991b612e0d565b60006117286524b9b9bab2b960d11b612e0d565b6000806000849050611805816040015182608001518360600151612bb1565b61180d612d17565b6001600160a01b0316638661cc7b82604001516040518263ffffffff1660e01b815260040161183e91815260200190565b602060405180830381865afa15801561185b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187f9190614a13565b156118cc5760405162461bcd60e51b815260206004820152601c60248201527f5372632073796e74682076616c756520697320766f6c6174696c652e000000006044820152606401610661565b6118d4612d17565b6001600160a01b0316638661cc7b82606001516040518263ffffffff1660e01b815260040161190591815260200190565b602060405180830381865afa158015611922573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119469190614a13565b156119935760405162461bcd60e51b815260206004820152601d60248201527f446573742073796e74682076616c756520697320766f6c6174696c652e0000006044820152606401610661565b6119aa816080015182600001518360400151612f22565b61010084015260e0830152608082018190526000036119d057600080925092505061136e565b6000806000806119ed85608001518660400151876060015161240f565b60a08b0186905260c08b0185905260408b015160608c0151969d50949b5092985090965094509250611a1e91612f5b565b15611a345760008096509650505050505061136e565b611a3c611793565b6001600160a01b03166378cb51cb84611a558a8a6123b0565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401602060405180830381865afa158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190614a13565b15611b075760405162461bcd60e51b815260206004820152601d60248201527f41746f6d6963207261746520646576696174657320746f6f206d7563680000006044820152606401610661565b6000631cd554d160e21b866040015103611b2657506080890151611b7c565b631cd554d160e21b866060015103611b3f575082611b7c565b600080611b5c8c608001518960400151631cd554d160e21b61240f565b5050505091509150611b7781836123b090919063ffffffff16565b925050505b611b858161307f565b611b8f868a61312b565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a606001518d8c60c001518d6101200151604051611c2096959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fa15ae7ed6a9ceafa6788f8020c73234a073e5fd311aca9b3250c93d374c07785886040015189608001518a606001518d8c60c001518d6101200151604051611cb996959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a35050505050509250929050565b6000546001600160a01b03163314611d405760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b6064820152608401610661565b565b60008060006060611d5161170d565b60405163b44e975360e01b81526001600160a01b03888116600483015260248201889052919091169063b44e975390604401602060405180830381865afa158015611da0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc49190614858565b915060008267ffffffffffffffff811115611de157611de161491e565b604051908082528060200260200182016040528015611e6057816020015b611e4d60405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611dff5790505b50905060005b838110156120a3576000806000611e7e8b8b866134a7565b9050600080611e8c836135cd565b915091506000611e9a612d17565b84516020860151604080880151905162d9ccd960e71b815260048101939093526024830191909152604482015260648101859052608481018490526001600160a01b039190911690636ce66c809060a401606060405180830381865afa158015611f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2c9190614b45565b505090506000611f40828660800151612d32565b90506000611f4c611793565b6001600160a01b03166378cb51cb8760600151846040518363ffffffff1660e01b8152600401611f86929190918252602082015260400190565b602060405180830381865afa158015611fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc79190614a13565b905080612027578186606001511115611ffc576060860151611fe99083612daf565b9750611ff58e896123b0565b9d50612027565b8560600151821115612027576060860151612018908390612daf565b96506120248d886123b0565b9c505b6040518061010001604052808760000151815260200187602001518152602001876040015181526020018981526020018881526020018681526020018581526020018760a001518152508a8a8151811061208357612083614a4d565b602002602001018190525050505050505050508080600101915050611e66565b50905092959194509250565b60008060006120cf6120c08561370c565b6120c98761370c565b906123b0565b905060006120dd8686612b35565b935090506120eb82826123b0565b935050509250929050565b600080600061210585856104bf565b1561215e5760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f7420736574746c6520647572696e672077616974696e67207065726044820152621a5bd960ea1b6064820152608401610661565b60008060008061216e8989611d42565b93509350935093508284111561219a576121888484612daf565b96506121958989896137e1565b6121b9565b838311156121b9576121ac8385612daf565b95506121b9898988613905565b60005b815181101561233557896001600160a01b03167f8e3ad1f68bec55de3b6fa12ae2674a2a683a17c918a4cbf5157ac5d9ddc6e94083838151811061220257612202614a4d565b60200260200101516000015184848151811061222057612220614a4d565b60200260200101516020015185858151811061223e5761223e614a4d565b60200260200101516040015186868151811061225c5761225c614a4d565b60200260200101516060015187878151811061227a5761227a614a4d565b60200260200101516080015188888151811061229857612298614a4d565b602002602001015160a001518989815181106122b6576122b6614a4d565b602002602001015160c001518a8a815181106122d4576122d4614a4d565b602002602001015160e00151604051612325989796959493929190978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405180910390a26001016121bc565b5081945061234161170d565b604051636869eb1560e11b81526001600160a01b038b81166004830152602482018b9052919091169063d0d3d62a90604401600060405180830381600087803b15801561238d57600080fd5b505af11580156123a1573d6000803e3d6000fd5b50505050505050509250925092565b6000806123bd8385614b89565b9050838110156105445760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610661565b6000806000806000806000612422612d17565b604051622a943760e51b8152600481018b9052602481018c9052604481018a90526001600160a01b03919091169063055286e090606401608060405180830381865afa158015612476573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249a9190614b9c565b9196509450925090506124ad8989613a20565b94506124b98186612d32565b96506124c58188612daf565b95505093975093979195509350565b60025460405162c8ac9760e41b8152600481018390526000916001600160a01b031690630c8ac97090602401602060405180830381865afa15801561251d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105479190614a30565b604080516001808252818301909252606091602080830190803683370190505090506e466c657869626c6553746f7261676560881b8160008151811061258957612589614a4d565b60200260200101818152505090565b6060815183516125a89190614b89565b67ffffffffffffffff8111156125c0576125c061491e565b6040519080825280602002602001820160405280156125e9578160200160208202803683370190505b50905060005b83518110156126375783818151811061260a5761260a614a4d565b602002602001015182828151811061262457612624614a4d565b60209081029190910101526001016125ef565b5060005b825181101561268f5782818151811061265657612656614a4d565b60200260200101518282865161266c9190614b89565b8151811061267c5761267c614a4d565b602090810291909101015260010161263b565b5092915050565b60008060008460800151116126db5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610661565b61271b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b612723612d17565b6001600160a01b0316637a018a1e86604001516040518263ffffffff1660e01b815260040161275491815260200190565b602060405180830381865afa158015612771573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127959190614858565b60a08201526127a2612d17565b6001600160a01b0316637a018a1e86606001516040518263ffffffff1660e01b81526004016127d391815260200190565b602060405180830381865afa1580156127f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128149190614858565b60c0820152608085015185516040870151612830929190612f22565b61010088015260e08701526080860181905260000361285657600080925092505061136e565b61285e612d17565b6040808701516080880151606089015160a086015160c0870151945162d9ccd960e71b8152600481019490945260248401929092526044830152606482015260848101919091526001600160a01b039190911690636ce66c809060a401606060405180830381865afa1580156128d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fc9190614b45565b60208401528252604080830191909152850151606086015160a083015160c084015161292a93929190613a57565b61293c85604001518660600151612f5b565b1561294e57600080925092505061136e565b600061296c866040015187606001518460a001518560c00151613be7565b60608401919091529050801561298a5760008093509350505061136e565b61299c82604001518360600151612d32565b60408301519094506129ae9085612daf565b60a0870185905260c0870181905292506129c8868661312b565b85602001516001600160a01b031686600001516001600160a01b03167f44dad12059e2c487e34548d3f2853cd851983ebd74f59ae89f55db7f0f5234ea886040015189608001518a60600151898c60c001518d6101200151604051612a5996959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a385602001516001600160a01b031686600001516001600160a01b03167fb5826da57a48b0e5d9160b88cdc4a9c303be1746b0619e42e51afe8fe353bbd9886040015189608001518a60600151898c60c001518d6101200151604051612af296959493929190958652602086019490945260408501929092526060840152608083015261ffff1660a082015260c00190565b60405180910390a36000612b04612e82565b1115612b2c57612b2c8660200151876040015188608001518960600151888760600151613c2c565b50509250929050565b6000806000612b42613e27565b9050600080612b51868461408c565b91509150600080612b62898661408c565b9092509050612b7184836123b0565b6060860151909750871180612b865787612b8c565b85606001515b9750878180612b985750845b80612ba05750825b975097505050505050509250929050565b60008211612bef5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610661565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612c2457612c24614a4d565b6020026020010181815250508181600181518110612c4457612c44614a4d565b602002602001018181525050612c58612d17565b6001600160a01b0316630a7d36d1826040518263ffffffff1660e01b8152600401612c8391906147ec565b602060405180830381865afa158015612ca0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc49190614a13565b15612d115760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e0000000000006044820152606401610661565b50505050565b60006117286c45786368616e6765526174657360981b612e0d565b6000610544612da8837306c1bad207a5ec045548238b8531087d8e03825263907af6c06040518163ffffffff1660e01b8152600401602060405180830381865af4158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061176c9190614858565b849061414a565b600082821115612e015760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f7700006044820152606401610661565b6000610dc58385614bd2565b600081815260036020908152604080832054905170026b4b9b9b4b7339030b2323932b9b99d1607d1b92810192909252603182018490526001600160a01b031690811515906051016040516020818303038152906040529061268f5760405162461bcd60e51b81526004016106619190614be5565b6000612e8c61416c565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527077616974696e67506572696f645365637360781b60248201526001600160a01b0391909116906323257c2b906044015b602060405180830381865afa158015612efe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117289190614858565b600080600080612f3286866120f6565b899650919450925090508015612f5157612f4e86868985610c3e565b93505b5093509350939050565b6000631cd554d160e21b8314612fe657612f73611793565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b8152600401612fa091815260200190565b60408051808303816000875af1158015612fbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe2919061487f565b9150505b631cd554d160e21b8214610547576000612ffe611793565b6001600160a01b031663a47af19e846040518263ffffffff1660e01b815260040161302b91815260200190565b60408051808303816000875af1158015613049573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061306d919061487f565b915082905080610dc557509392505050565b60045460009067ffffffffffffffff16421461309b57816130b8565b6004546130b890600160401b90046001600160c01b0316836123b0565b90506130c2614189565b81111561310a5760405162461bcd60e51b815260206004820152601660248201527514dd5c9c185cdcd959081d9bdb1d5b59481b1a5b5a5d60521b6044820152606401610661565b6001600160c01b0316600160401b0267ffffffffffffffff42161760045550565b6131336117d2565b6001600160a01b0316633260803983604001516040518263ffffffff1660e01b815260040161316491815260200190565b602060405180830381865afa158015613181573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a59190614a30565b82516080840151604051632770a7eb60e21b81526001600160a01b0392831660048201526024810191909152911690639dc29fac90604401600060405180830381600087803b1580156131f757600080fd5b505af115801561320b573d6000803e3d6000fd5b5050505081610120015161ffff1660000361330e57600061322a6117d2565b6001600160a01b0316633260803984606001516040518263ffffffff1660e01b815260040161325b91815260200190565b602060405180830381865afa158015613278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329c9190614a30565b602084015160a085015160405163219e412d60e21b81526001600160a01b039283166004820152602481019190915291925082169063867904b490604401600060405180830381600087803b1580156132f457600080fd5b505af1158015613308573d6000803e3d6000fd5b50505050505b60008260c0015111801561332d5750631cd554d160e21b826060015114155b156133c85761333a612d17565b606083015160c0840151604051631952982b60e21b815260048101929092526024820152631cd554d160e21b60448201526001600160a01b03919091169063654a60ac90606401602060405180830381865afa15801561339e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c29190614858565b60c08301525b6133d1816124d4565b82516040808501516060860151608087015160a088015160e08901516101008a015160c08b01516101208c01516101408d01519851632028bac560e21b81526001600160a01b039a8b166004820152602481019890985260448801969096526064870194909452608486019290925260a485015260c484015260e483015261ffff166101048201529015156101248201529116906380a2eb14903490610144016000604051808303818588803b15801561348a57600080fd5b505af115801561349e573d6000803e3d6000fd5b50505050505050565b6134f560405180610100016040528060008019168152602001600081526020016000801916815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008060008060008060008061350961170d565b604051630acc3f5b60e11b81526001600160a01b038e81166004830152602482018e9052604482018d905291909116906315987eb69060640161010060405180830381865afa158015613560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135849190614bf8565b60408051610100810182529889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201529c9b505050505050505050505050565b60008060006135da612d17565b905060006135e6612e82565b855160c087015160a088015160405163084f235160e11b8152600481019390935260248301919091526044820152606481018290529091506001600160a01b0383169063109e46a290608401602060405180830381865afa15801561364f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136739190614858565b60408681015160e088015160a0890151925163084f235160e11b8152600481019290925260248201526044810191909152606481018390529094506001600160a01b0383169063109e46a290608401602060405180830381865afa1580156136df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137039190614858565b92505050915091565b600061371661416c565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6e65786368616e67654665655261746560881b85604051602001613764929190918252602082015260400190565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b81526004016137a0929190918252602082015260400190565b602060405180830381865afa1580156137bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105479190614858565b6137e96117d2565b6001600160a01b03166332608039836040518263ffffffff1660e01b815260040161381691815260200190565b602060405180830381865afa158015613833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138579190614a30565b604051632770a7eb60e21b81526001600160a01b038581166004830152602482018490529190911690639dc29fac90604401600060405180830381600087803b1580156138a357600080fd5b505af11580156138b7573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f491df6adf9cabe8ca514806effd6b6b6475572dc88fe4b8b58d0a20ecf45e1059250015b60405180910390a2505050565b61390d6117d2565b6001600160a01b03166332608039836040518263ffffffff1660e01b815260040161393a91815260200190565b602060405180830381865afa158015613957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061397b9190614a30565b60405163219e412d60e21b81526001600160a01b03858116600483015260248201849052919091169063867904b490604401600060405180830381600087803b1580156139c757600080fd5b505af11580156139db573d6000803e3d6000fd5b505060408051858152602081018590526001600160a01b03871693507f93751433c6897553c8950f14ccc193ccffb8f539f7421ffde9af83b9b7dae1a89250016138f8565b600080613a38613a2f846141f8565b6120c9866141f8565b90508060000361054457610dc5613a4e8461370c565b6120c98661370c565b6040805160028082526060820183526000926020830190803683370190505090508481600081518110613a8c57613a8c614a4d565b6020026020010181815250508381600181518110613aac57613aac614a4d565b6020908102919091010152604080516002808252606082019092526000918160200160208202803683370190505090508381600081518110613af057613af0614a4d565b6020026020010181815250508281600181518110613b1057613b10614a4d565b602002602001018181525050613b24612d17565b6001600160a01b031663d89ee86183836040518363ffffffff1660e01b8152600401613b51929190614c55565b602060405180830381865afa158015613b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b929190614a13565b15613bdf5760405162461bcd60e51b815260206004820152601a60248201527f7372632f646573742076616c756520697320696e76616c69642e0000000000006044820152606401610661565b505050505050565b6000806000613c01613bf88761370c565b6120c98961370c565b90506000613c1188888888614256565b93509050613c1f82826123b0565b9350505094509492505050565b6000613c36612d17565b604051633d00c50f60e11b8152600481018890529091506000906001600160a01b03831690637a018a1e90602401602060405180830381865afa158015613c81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ca59190614858565b604051633d00c50f60e11b8152600481018790529091506000906001600160a01b03841690637a018a1e90602401602060405180830381865afa158015613cf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d149190614858565b9050613d1e61170d565b604051630f2a761760e21b81526001600160a01b038b81166004830152602482018b9052604482018a9052606482018990526084820188905260a482018790524260c483015260e4820185905261010482018490529190911690633ca9d85c9061012401600060405180830381600087803b158015613d9c57600080fd5b505af1158015613db0573d6000803e3d6000fd5b5050604080518b8152602081018b9052908101899052606081018890526080810187905260a0810185905260c081018490526001600160a01b038c1692507f62e40d554c7abcdd31074960d8347a2225daeb04d93bc748f049ba2ce9462398915060e00160405180910390a2505050505050505050565b613e526040518060800160405280600081526020016000815260200160008152602001600081525090565b60408051600480825260a08201909252600091602082016080803683370190505090507f65786368616e676544796e616d69634665655468726573686f6c64000000000081600081518110613ea957613ea9614a4d565b6020026020010181815250507f65786368616e676544796e616d6963466565576569676874446563617900000081600181518110613ee957613ee9614a4d565b6020026020010181815250507f65786368616e676544796e616d6963466565526f756e6473000000000000000081600281518110613f2957613f29614a4d565b6020026020010181815250507465786368616e67654d617844796e616d696346656560581b81600381518110613f6157613f61614a4d565b6020026020010181815250506000613f7761416c565b6001600160a01b031663b67fa7ed6d53797374656d53657474696e677360901b846040518363ffffffff1660e01b8152600401613fb5929190614cac565b600060405180830381865afa158015613fd2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ffa9190810190614d63565b905060405180608001604052808260008151811061401a5761401a614a4d565b602002602001015181526020018260018151811061403a5761403a614a4d565b602002602001015181526020018260028151811061405a5761405a614a4d565b602002602001015181526020018260038151811061407a5761407a614a4d565b60200260200101518152509250505090565b600080631cd554d160e21b8414806140a957506001836040015111155b156140b95750600090508061136e565b60006140c3612d17565b6001600160a01b0316637a018a1e866040518263ffffffff1660e01b81526004016140f091815260200190565b602060405180830381865afa15801561410d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141319190614858565b905061413e8582866142d6565b92509250509250929050565b60006141586012600a614e7c565b61416284846143d1565b6105449190614e88565b60006117286e466c657869626c6553746f7261676560881b612e0d565b600061419361416c565b6040516323257c2b60e01b81526d53797374656d53657474696e677360901b60048201527f61746f6d69634d6178566f6c756d65506572426c6f636b00000000000000000060248201526001600160a01b0391909116906323257c2b90604401612ee1565b600061420261416c565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7461746f6d696345786368616e67654665655261746560581b85604051602001613764929190918252602082015260400190565b6000806000614263613e27565b90506000806142738887856142d6565b915091506000806142858b8a876142d6565b909250905061429484836123b0565b60608601519097508711806142a957876142af565b85606001515b97508781806142bb5750845b806142c35750825b9750975050505050505094509492505050565b600080631cd554d160e21b8514806142f357506001836040015111155b15614303575060009050806143c9565b606061430d612d17565b6040808601519051630ed7624560e41b8152600481018990526024810191909152604481018790526001600160a01b03919091169063ed76245090606401600060405180830381865afa158015614368573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526143909190810190614eaa565b50809150506143a88185600001518660200151614453565b60608501519093508311806143bd57836143c3565b84606001515b93509150505b935093915050565b6000826000036143e357506000610547565b60006143ef8385614f0e565b9050826143fc8583614e88565b146105445760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b6064820152608401610661565b6000835160000361446657506000611772565b600080600186516144779190614bd2565b90505b8015610d445761448a828561414a565b915060006144d58761449d600185614bd2565b815181106144ad576144ad614a4d565b60200260200101518884815181106144c7576144c7614a4d565b6020026020010151886144f7565b90506144e183826123b0565b92505080806144ef90614f25565b91505061447a565b60008260000361450957506000611772565b60008385116145215761451c8585614bd2565b61452b565b61452b8486614bd2565b90506000614539828661455d565b9050838111614549576000614553565b6145538482614bd2565b9695505050505050565b6000610544826145796145726012600a614e7c565b86906143d1565b9060008082116145cb5760405162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f0000000000006044820152606401610661565b6000610dc58385614e88565b6001600160a01b03811681146145ec57600080fd5b50565b80356145fa816145d7565b919050565b6000806040838503121561461257600080fd5b823561461d816145d7565b946020939093013593505050565b60006020828403121561463d57600080fd5b5035919050565b6000610160828403121561465757600080fd5b50919050565b60008060006101a0848603121561467357600080fd5b833592506146848560208601614644565b915061018084013590509250925092565b6000806000606084860312156146aa57600080fd5b83356146b5816145d7565b95602085013595506040909401359392505050565b6000602082840312156146dc57600080fd5b8135610544816145d7565b600080604083850312156146fa57600080fd5b50508035926020909101359150565b6000806000806080858703121561471f57600080fd5b843561472a816145d7565b966020860135965060408601359560600135945092505050565b803561ffff811681146145fa57600080fd5b60008060008060008060c0878903121561476f57600080fd5b863561477a816145d7565b9550602087013594506040870135935060608701359250608087013591506147a460a08801614744565b90509295509295509295565b60008151808452602080850194506020840160005b838110156147e1578151875295820195908201906001016147c5565b509495945050505050565b60208152600061054460208301846147b0565b600080610180838503121561481357600080fd5b61481d8484614644565b94610160939093013593505050565b60008060006060848603121561484157600080fd5b505081359360208301359350604090920135919050565b60006020828403121561486a57600080fd5b5051919050565b80151581146145ec57600080fd5b6000806040838503121561489257600080fd5b8251915060208301516148a481614871565b809150509250929050565b60208082526049908201527f45786368616e6765723a204f6e6c79207772617070656453796e746872206f7260408201527f20612073796e746820636f6e74726163742063616e20706572666f726d20746860608201526834b99030b1ba34b7b760b91b608082015260a00190565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff811182821017156149585761495861491e565b60405290565b80356145fa81614871565b6000610160828403121561497c57600080fd5b614984614934565b61498d836145ef565b815261499b602084016145ef565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206149f6818501614744565b90820152610140614a0884820161495e565b908201529392505050565b600060208284031215614a2557600080fd5b815161054481614871565b600060208284031215614a4257600080fd5b8151610544816145d7565b634e487b7160e01b600052603260045260246000fd5b6000815180845260005b81811015614a8957602081850181015186830182015201614a6d565b506000602082860101526020601f19601f83011685010191505092915050565b600061010061ffff808c168452816020850152614ac88285018c614a63565b604085019a909a5260608401989098525050608081019490945260a084019290925260c083015290911660e09091015292915050565b606081526000614b116060830186614a63565b61ffff94851660208401529290931660409091015292915050565b828152604060208201526000610dc56040830184614a63565b600080600060608486031215614b5a57600080fd5b8351925060208401519150604084015190509250925092565b634e487b7160e01b600052601160045260246000fd5b8082018082111561054757610547614b73565b60008060008060808587031215614bb257600080fd5b505082516020840151604085015160609095015191969095509092509050565b8181038181111561054757610547614b73565b6020815260006105446020830184614a63565b600080600080600080600080610100898b031215614c1557600080fd5b505086516020880151604089015160608a015160808b015160a08c015160c08d015160e0909d0151959e949d50929b919a50985090965094509092509050565b604081526000614c6860408301856147b0565b82810360208481019190915284518083528582019282019060005b81811015614c9f57845183529383019391830191600101614c83565b5090979650505050505050565b828152604060208201526000610dc560408301846147b0565b600082601f830112614cd657600080fd5b8151602067ffffffffffffffff80831115614cf357614cf361491e565b8260051b604051601f19603f83011681018181108482111715614d1857614d1861491e565b6040529384526020818701810194908101925087851115614d3857600080fd5b6020870191505b84821015614d5857815183529183019190830190614d3f565b979650505050505050565b600060208284031215614d7557600080fd5b815167ffffffffffffffff811115614d8c57600080fd5b610dc584828501614cc5565b600181815b80851115614dd3578160001904821115614db957614db9614b73565b80851615614dc657918102915b93841c9390800290614d9d565b509250929050565b600082614dea57506001610547565b81614df757506000610547565b8160018114614e0d5760028114614e1757614e33565b6001915050610547565b60ff841115614e2857614e28614b73565b50506001821b610547565b5060208310610133831016604e8410600b8410161715614e56575081810a610547565b614e608383614d98565b8060001904821115614e7457614e74614b73565b029392505050565b60006105448383614ddb565b600082614ea557634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215614ebd57600080fd5b825167ffffffffffffffff80821115614ed557600080fd5b614ee186838701614cc5565b93506020850151915080821115614ef757600080fd5b50614f0485828601614cc5565b9150509250929050565b808202811582820484141761054757610547614b73565b600081614f3457614f34614b73565b50600019019056fea26469706673582212207fe994478d6b73905bbc3168c0055d72301be88244b4564734008004f91e4af064736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006f808ae3445a711ecaa4da5c8330b051541a4de000000000000000000000000049a6e93768f0ba860c578da3b7b8de3b9b29f7ed
-----Decoded View---------------
Arg [0] : _owner (address): 0x6F808aE3445A711ecAa4DA5c8330B051541A4dE0
Arg [1] : _resolver (address): 0x49a6E93768f0Ba860c578dA3B7b8DE3B9b29F7eD
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000006f808ae3445a711ecaa4da5c8330b051541a4de0
Arg [1] : 00000000000000000000000049a6e93768f0ba860c578da3b7b8de3b9b29f7ed
Loading...
Loading
Loading...
Loading
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.