From 5b0cda888575ebd75b081eb157a000029d018f99 Mon Sep 17 00:00:00 2001 From: Lecky Date: Sat, 25 Dec 2021 22:12:00 +1100 Subject: [PATCH 01/11] Merge branch 'develop' into feat/sip-184-dynamic-fees --- contracts/ExchangeRates.sol | 230 +-- contracts/ExchangeRatesWithDexPricing.sol | 8 +- contracts/interfaces/IExchangeRates.sol | 4 - hardhat.config.js | 1 + index.js | 4 +- package-lock.json | 4 +- package.json | 2 +- publish/assets.json | 6 + publish/deployed/kovan-ovm/config.json | 3 + publish/deployed/kovan-ovm/deployment.json | 1335 +++++++++++++++- publish/deployed/kovan-ovm/params.json | 11 +- publish/deployed/kovan-ovm/versions.json | 41 +- publish/deployed/local-ovm/params.json | 11 +- publish/deployed/mainnet-ovm/config.json | 3 + publish/deployed/mainnet-ovm/deployment.json | 1337 +++++++++++++++- publish/deployed/mainnet-ovm/params.json | 11 +- publish/deployed/mainnet-ovm/versions.json | 25 +- publish/deployed/mainnet/config.json | 9 + publish/deployed/mainnet/deployment.json | 149 +- publish/deployed/mainnet/feeds.json | 4 + publish/deployed/mainnet/synths.json | 5 + publish/deployed/mainnet/versions.json | 25 + publish/releases.json | 28 +- .../src/commands/deploy/configure-loans.js | 10 +- .../deploy/configure-system-settings.js | 6 +- publish/src/commands/deploy/deploy-core.js | 3 +- publish/src/commands/deploy/index.js | 4 - .../deploy/rebuild-resolver-caches.js | 4 +- .../deploy/system-and-parameter-check.js | 18 +- publish/src/commands/owner.js | 156 +- test/contracts/BaseSynthetix.js | 74 +- test/contracts/CollateralErc20.js | 54 +- test/contracts/CollateralEth.js | 60 +- test/contracts/CollateralManager.js | 25 +- test/contracts/CollateralShort.js | 57 +- test/contracts/CollateralUtil.js | 57 +- test/contracts/DebtCache.js | 92 +- test/contracts/Depot.js | 29 +- test/contracts/EtherWrapper.js | 15 +- test/contracts/ExchangeRates.js | 1387 +++-------------- test/contracts/Exchanger.spec.js | 223 +-- test/contracts/FeePool.js | 69 +- test/contracts/FeePoolState.js | 16 +- test/contracts/Issuer.js | 121 +- test/contracts/Liquidations.js | 13 +- test/contracts/MultiCollateralSynth.js | 39 +- test/contracts/NativeEtherWrapper.js | 15 +- test/contracts/PurgeableSynth.js | 26 +- test/contracts/RewardsIntegrationTests.js | 57 +- test/contracts/ShortingRewards.js | 49 +- test/contracts/StakingRewards.js | 23 +- test/contracts/Synth.js | 26 +- test/contracts/SynthUtil.js | 25 +- test/contracts/Synthetix.js | 25 +- test/contracts/TradingRewards.spec.js | 25 +- test/contracts/Wrapper.js | 17 +- test/contracts/WrapperFactory.js | 15 +- test/contracts/helpers.js | 76 +- test/contracts/setup.js | 27 +- .../behaviors/exchange.behavior.js | 6 +- test/integration/behaviors/redeem.behavior.js | 4 +- test/integration/behaviors/stake.behavior.js | 9 +- test/integration/utils/bootstrap.js | 10 +- test/integration/utils/rates.js | 66 +- test/integration/utils/skip.js | 4 +- test/publish/index.js | 16 +- test/utils/index.js | 13 + 67 files changed, 3699 insertions(+), 2623 deletions(-) diff --git a/contracts/ExchangeRates.sol b/contracts/ExchangeRates.sol index ac0902db53..c3bae1220c 100644 --- a/contracts/ExchangeRates.sol +++ b/contracts/ExchangeRates.sol @@ -22,12 +22,8 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { using SafeDecimalMath for uint; bytes32 public constant CONTRACT_NAME = "ExchangeRates"; - - // Exchange rates and update times stored by currency code, e.g. 'SNX', or 'sUSD' - mapping(bytes32 => mapping(uint => RateAndUpdatedTime)) private _rates; - - // The address of the oracle which pushes rate updates to this contract - address public oracle; + //slither-disable-next-line naming-convention + bytes32 internal constant sUSD = "sUSD"; // Decentralized oracle networks that feed into pricing aggregators mapping(bytes32 => AggregatorV2V3Interface) public aggregators; @@ -37,61 +33,12 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { // List of aggregator keys for convenient iteration bytes32[] public aggregatorKeys; - // Do not allow the oracle to submit times any further forward into the future than this constant. - uint private constant ORACLE_FUTURE_LIMIT = 10 minutes; - - /// @notice ID for the current round - /// @param currencyKey is the currency key of the synth to be exchanged - /// @return the current exchange round ID - mapping(bytes32 => uint) public currentRoundForRate; - - // // ========== CONSTRUCTOR ========== - constructor( - address _owner, - address _oracle, - address _resolver, - bytes32[] memory _currencyKeys, - uint[] memory _newRates - ) public Owned(_owner) MixinSystemSettings(_resolver) { - require(_currencyKeys.length == _newRates.length, "Currency key length and rate length must match."); - - oracle = _oracle; - - // The sUSD rate is always 1 and is never stale. - _setRate("sUSD", 0, SafeDecimalMath.unit(), now); - - internalUpdateRates(_currencyKeys, _newRates, now); - } - - /* ========== SETTERS ========== */ - - function setOracle(address _oracle) external onlyOwner { - oracle = _oracle; - emit OracleUpdated(oracle); - } + constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) {} /* ========== MUTATIVE FUNCTIONS ========== */ - function updateRates( - bytes32[] calldata currencyKeys, - uint[] calldata newRates, - uint timeSent - ) external onlyOracle returns (bool) { - return internalUpdateRates(currencyKeys, newRates, timeSent); - } - - function deleteRate(bytes32 currencyKey) external onlyOracle { - require(_getRate(currencyKey) > 0, "Rate is zero"); - - delete _rates[currencyKey][currentRoundForRate[currencyKey]]; - - currentRoundForRate[currencyKey]--; - - emit RateDeleted(currencyKey); - } - function addAggregator(bytes32 currencyKey, address aggregatorAddress) external onlyOwner { AggregatorV2V3Interface aggregator = AggregatorV2V3Interface(aggregatorAddress); // This check tries to make sure that a valid aggregator is being added. @@ -341,7 +288,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid) { RateAndUpdatedTime memory rateAndTime = _getRateAndUpdatedTime(currencyKey); - if (currencyKey == "sUSD") { + if (currencyKey == sUSD) { return (rateAndTime.rate, false); } return ( @@ -367,7 +314,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { // do one lookup of the rate & time to minimize gas RateAndUpdatedTime memory rateEntry = _getRateAndUpdatedTime(currencyKeys[i]); rates[i] = rateEntry.rate; - if (!anyRateInvalid && currencyKeys[i] != "sUSD") { + if (!anyRateInvalid && currencyKeys[i] != sUSD) { anyRateInvalid = flagList[i] || _rateIsStaleWithTime(_rateStalePeriod, rateEntry.time); } } @@ -425,64 +372,6 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { } } - /// @notice setting the rate for a currency - /// @param currencyKey the currency key - /// @param roundId the round id - /// @param rate the rate to set - /// @param time the time of the rate - function _setRate( - bytes32 currencyKey, - uint256 roundId, - uint256 rate, - uint256 time - ) internal { - if (roundId > 0) { - currentRoundForRate[currencyKey] = roundId; - } else { - // Note: this will effectively start the rounds at 1, which matches Chainlink's Agggregators - currentRoundForRate[currencyKey]++; - } - - // skip writing if the rate is the same - if (rate == _rates[currencyKey][currentRoundForRate[currencyKey]].rate) return; - - _rates[currencyKey][currentRoundForRate[currencyKey]] = RateAndUpdatedTime({ - rate: uint216(rate), - time: uint40(time) - }); - } - - function internalUpdateRates( - bytes32[] memory currencyKeys, - uint[] memory newRates, - uint timeSent - ) internal returns (bool) { - require(currencyKeys.length == newRates.length, "Currency key array length must match rates array length."); - require(timeSent < (now + ORACLE_FUTURE_LIMIT), "Time is too far into the future"); - - // Loop through each key and perform update. - for (uint i = 0; i < currencyKeys.length; i++) { - bytes32 currencyKey = currencyKeys[i]; - - // Should not set any rate to zero ever, as no asset will ever be - // truely worthless and still valid. In this scenario, we should - // delete the rate and remove it from the system. - require(newRates[i] != 0, "Zero is not a valid rate, please call deleteRate instead."); - require(currencyKey != "sUSD", "Rate of sUSD cannot be updated, it's always UNIT."); - - // We should only update the rate if it's at least the same age as the last rate we've got. - if (timeSent < _getUpdatedTime(currencyKey)) { - continue; - } - - _setRate(currencyKey, 0, newRates[i], timeSent); - } - - emit RatesUpdated(currencyKeys, newRates); - - return true; - } - function removeFromArray(bytes32 entry, bytes32[] storage array) internal returns (bool) { for (uint i = 0; i < array.length; i++) { if (array[i] == entry) { @@ -511,59 +400,65 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { return uint(rate); } - function _getRateAndUpdatedTime(bytes32 currencyKey) internal view returns (RateAndUpdatedTime memory entry) { - AggregatorV2V3Interface aggregator = aggregators[currencyKey]; - - if (aggregator != AggregatorV2V3Interface(0)) { - // this view from the aggregator is the most gas efficient but it can throw when there's no data, - // so let's call it low-level to suppress any reverts - bytes memory payload = abi.encodeWithSignature("latestRoundData()"); - // solhint-disable avoid-low-level-calls - (bool success, bytes memory returnData) = address(aggregator).staticcall(payload); - - if (success) { - (, int256 answer, , uint256 updatedAt, ) = - abi.decode(returnData, (uint80, int256, uint256, uint256, uint80)); - entry.rate = uint216(_formatAggregatorAnswer(currencyKey, answer)); - entry.time = uint40(updatedAt); - } + function _getRateAndUpdatedTime(bytes32 currencyKey) internal view returns (RateAndUpdatedTime memory) { + // sUSD rate is 1.0 + if (currencyKey == sUSD) { + return RateAndUpdatedTime({rate: uint216(SafeDecimalMath.unit()), time: 0}); } else { - uint roundId = currentRoundForRate[currencyKey]; - entry = _rates[currencyKey][roundId]; + AggregatorV2V3Interface aggregator = aggregators[currencyKey]; + if (aggregator != AggregatorV2V3Interface(0)) { + // this view from the aggregator is the most gas efficient but it can throw when there's no data, + // so let's call it low-level to suppress any reverts + bytes memory payload = abi.encodeWithSignature("latestRoundData()"); + // solhint-disable avoid-low-level-calls + // slither-disable-next-line low-level-calls + (bool success, bytes memory returnData) = address(aggregator).staticcall(payload); + + if (success) { + (, int256 answer, , uint256 updatedAt, ) = + abi.decode(returnData, (uint80, int256, uint256, uint256, uint80)); + return + RateAndUpdatedTime({ + rate: uint216(_formatAggregatorAnswer(currencyKey, answer)), + time: uint40(updatedAt) + }); + } // else return defaults, to avoid reverting in views + } // else return defaults, to avoid reverting in views } } function _getCurrentRoundId(bytes32 currencyKey) internal view returns (uint) { + if (currencyKey == sUSD) { + return 0; // no roundIds for sUSD + } AggregatorV2V3Interface aggregator = aggregators[currencyKey]; - if (aggregator != AggregatorV2V3Interface(0)) { return aggregator.latestRound(); - } else { - return currentRoundForRate[currencyKey]; - } + } // else return defaults, to avoid reverting in views } function _getRateAndTimestampAtRound(bytes32 currencyKey, uint roundId) internal view returns (uint rate, uint time) { - AggregatorV2V3Interface aggregator = aggregators[currencyKey]; - RateAndUpdatedTime memory update = _rates[currencyKey][roundId]; - - // Try to get rate from cache if possible - if (update.rate > 0) { - return (update.rate, update.time); - } - - if (aggregator != AggregatorV2V3Interface(0)) { - // this view from the aggregator is the most gas efficient but it can throw when there's no data, - // so let's call it low-level to suppress any reverts - bytes memory payload = abi.encodeWithSignature("getRoundData(uint80)", roundId); - // solhint-disable avoid-low-level-calls - (bool success, bytes memory returnData) = address(aggregator).staticcall(payload); - - if (success) { - (, int256 answer, , uint256 updatedAt, ) = - abi.decode(returnData, (uint80, int256, uint256, uint256, uint80)); - return (_formatAggregatorAnswer(currencyKey, answer), updatedAt); - } + // short circuit sUSD + if (currencyKey == sUSD) { + // sUSD has no rounds, and 0 time is preferrable for "volatility" heuristics + // which are used in atomic swaps and fee reclamation + return (SafeDecimalMath.unit(), 0); + } else { + AggregatorV2V3Interface aggregator = aggregators[currencyKey]; + + if (aggregator != AggregatorV2V3Interface(0)) { + // this view from the aggregator is the most gas efficient but it can throw when there's no data, + // so let's call it low-level to suppress any reverts + bytes memory payload = abi.encodeWithSignature("getRoundData(uint80)", roundId); + // solhint-disable avoid-low-level-calls + (bool success, bytes memory returnData) = address(aggregator).staticcall(payload); + + if (success) { + (, int256 answer, , uint256 updatedAt, ) = + abi.decode(returnData, (uint80, int256, uint256, uint256, uint80)); + return (_formatAggregatorAnswer(currencyKey, answer), updatedAt); + } // else return defaults, to avoid reverting in views + } // else return defaults, to avoid reverting in views } } @@ -605,7 +500,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function _rateIsStale(bytes32 currencyKey, uint _rateStalePeriod) internal view returns (bool) { // sUSD is a special case and is never stale (check before an SLOAD of getRateAndUpdatedTime) - if (currencyKey == "sUSD") return false; + if (currencyKey == sUSD) return false; return _rateIsStaleWithTime(_rateStalePeriod, _getUpdatedTime(currencyKey)); } @@ -616,7 +511,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function _rateIsFlagged(bytes32 currencyKey, FlagsInterface flags) internal view returns (bool) { // sUSD is a special case and is never invalid - if (currencyKey == "sUSD") return false; + if (currencyKey == sUSD) return false; address aggregator = address(aggregators[currencyKey]); // when no aggregator or when the flags haven't been setup if (aggregator == address(0) || flags == FlagsInterface(0)) { @@ -626,25 +521,12 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { } function _notImplemented() internal pure { + // slither-disable-next-line dead-code revert("Cannot be run on this layer"); } - /* ========== MODIFIERS ========== */ - - modifier onlyOracle { - _onlyOracle(); - _; - } - - function _onlyOracle() internal view { - require(msg.sender == oracle, "Only the oracle can perform this action"); - } - /* ========== EVENTS ========== */ - event OracleUpdated(address newOracle); - event RatesUpdated(bytes32[] currencyKeys, uint[] newRates); - event RateDeleted(bytes32 currencyKey); event AggregatorAdded(bytes32 currencyKey, address aggregator); event AggregatorRemoved(bytes32 currencyKey, address aggregator); } diff --git a/contracts/ExchangeRatesWithDexPricing.sol b/contracts/ExchangeRatesWithDexPricing.sol index 1548a61030..b6081da974 100644 --- a/contracts/ExchangeRatesWithDexPricing.sol +++ b/contracts/ExchangeRatesWithDexPricing.sol @@ -10,13 +10,7 @@ contract ExchangeRatesWithDexPricing is ExchangeRates { bytes32 internal constant SETTING_DEX_PRICE_AGGREGATOR = "dexPriceAggregator"; - constructor( - address _owner, - address _oracle, - address _resolver, - bytes32[] memory _currencyKeys, - uint[] memory _newRates - ) public ExchangeRates(_owner, _oracle, _resolver, _currencyKeys, _newRates) {} + constructor(address _owner, address _resolver) public ExchangeRates(_owner, _resolver) {} /* ========== SETTERS ========== */ diff --git a/contracts/interfaces/IExchangeRates.sol b/contracts/interfaces/IExchangeRates.sol index 5ed0ffdf2c..f1110010c8 100644 --- a/contracts/interfaces/IExchangeRates.sol +++ b/contracts/interfaces/IExchangeRates.sol @@ -15,8 +15,6 @@ interface IExchangeRates { function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool); - function currentRoundForRate(bytes32 currencyKey) external view returns (uint); - function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory); function effectiveValue( @@ -85,8 +83,6 @@ interface IExchangeRates { function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256); - function oracle() external view returns (address); - function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time); function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time); diff --git a/hardhat.config.js b/hardhat.config.js index 8b769f2504..d349c6031f 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -65,5 +65,6 @@ module.exports = { }, mocha: { timeout: 120e3, // 120s + retries: 3, }, }; diff --git a/index.js b/index.js index 5b66697ea9..b0db24ef56 100644 --- a/index.js +++ b/index.js @@ -193,8 +193,8 @@ const defaults = { }, ETHER_WRAPPER_MAX_ETH: w3utils.toWei('5000'), - ETHER_WRAPPER_MINT_FEE_RATE: w3utils.toWei('0.02'), // 200 bps - ETHER_WRAPPER_BURN_FEE_RATE: w3utils.toWei('0.0005'), // 5 bps + ETHER_WRAPPER_MINT_FEE_RATE: w3utils.toWei('0.005'), // 5 bps + ETHER_WRAPPER_BURN_FEE_RATE: '0', // SIP-120 ATOMIC_MAX_VOLUME_PER_BLOCK: w3utils.toWei(`${2e5}`), // 200k diff --git a/package-lock.json b/package-lock.json index a3bffd203a..29f81add21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "synthetix", - "version": "2.55.0", + "version": "2.56.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "2.55.0", + "version": "2.56.1", "license": "MIT", "dependencies": { "abi-decoder": "2.3.0", diff --git a/package.json b/package.json index 2536d81a40..aa01c63629 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "synthetix", - "version": "2.55.0", + "version": "2.56.1", "license": "MIT", "author": "Synthetix", "description": "The smart contracts which make up the Synthetix system. (synthetix.io)", diff --git a/publish/assets.json b/publish/assets.json index 35b05e6ae1..4dfcafc58a 100644 --- a/publish/assets.json +++ b/publish/assets.json @@ -239,6 +239,12 @@ "sign": "", "description": "DeFi Index" }, + "ETHBTC": { + "asset": "ETHBTC", + "category": "crypto", + "sign": "", + "description": "ETH / BTC" + }, "EUR": { "asset": "EUR", "category": "forex", diff --git a/publish/deployed/kovan-ovm/config.json b/publish/deployed/kovan-ovm/config.json index 41cad666e2..e273a64a5f 100644 --- a/publish/deployed/kovan-ovm/config.json +++ b/publish/deployed/kovan-ovm/config.json @@ -181,5 +181,8 @@ }, "OwnerRelayOnOptimism": { "deploy": false + }, + "CollateralEth": { + "deploy": false } } diff --git a/publish/deployed/kovan-ovm/deployment.json b/publish/deployed/kovan-ovm/deployment.json index 544b60e9bc..bf603e0ecf 100644 --- a/publish/deployed/kovan-ovm/deployment.json +++ b/publish/deployed/kovan-ovm/deployment.json @@ -209,10 +209,10 @@ }, "Synthetix": { "name": "Synthetix", - "address": "0xCAA5c8e9E67BBa010D2D7F589F02d588Fb49f93D", + "address": "0x099B3881d63d3Eef0ec32783Aa64B726672213E2", "source": "MintableSynthetix", - "link": "https://kovan-explorer.optimism.io/address/0xCAA5c8e9E67BBa010D2D7F589F02d588Fb49f93D", - "timestamp": "2021-10-11T16:31:00.378Z", + "link": "https://kovan-explorer.optimism.io/address/0x099B3881d63d3Eef0ec32783Aa64B726672213E2", + "timestamp": "2021-12-15T07:19:24.524Z", "txn": "", "network": "kovan" }, @@ -566,6 +566,15 @@ "timestamp": "2021-11-22T21:36:24.000Z", "txn": "https://kovan-explorer.optimism.io/tx/0x7977a8dbfbdf8a0154b1e38500420b6a8b5fc6ff8937d7ed4ea66d33fbbbccc3", "network": "kovan" + }, + "CollateralEth": { + "name": "CollateralEth", + "address": "0xc7960401a5Ca5A201d41Cf6532C7d2803f8D5Ce4", + "source": "CollateralEth", + "link": "https://kovan-explorer.optimism.io/address/0xc7960401a5Ca5A201d41Cf6532C7d2803f8D5Ce4", + "timestamp": "2021-12-15T07:19:30.068Z", + "txn": "", + "network": "kovan" } }, "sources": { @@ -14826,7 +14835,7 @@ } }, "MintableSynthetix": { - "bytecode": "60806040523480156200001c57600080620000196200039d565b50505b506040516200579538038062005795833981810160405260a08110156200004d576000806200004a6200039d565b50505b8101908080519291906020018051929190602001805192919060200180519291906020018051925086915085905084848480858560405160408082018152601782527f53796e746865746978204e6574776f726b20546f6b656e0000000000000000006020830152516040808201905260038152620a69cb60eb1b60208201528660128986816001600160a01b038116620001395760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015260640160405180910390620001366200039d565b50505b806000600181620001496200040a565b816001600160a01b0302191690836001600160a01b03160217906200016d6200046c565b5050507fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c6000826040516001600160a01b039283168152911660208201526040908101905180910390a15060008080620001c66200040a565b906101000a90046001600160a01b03166001600160a01b03161415620002315760405162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b6044820152606401604051809103906200022e6200039d565b50505b806002600181620002416200040a565b816001600160a01b0302191690836001600160a01b0316021790620002656200046c565b5050507ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e816040516001600160a01b03909116815260200160405180910390a150856005600181620002b66200040a565b816001600160a01b0302191690836001600160a01b0316021790620002da6200046c565b505050846006908051620002f3929160200190620004bb565b50600784805162000309929160200190620004bb565b5082806008620003186200046c565b50505081600960006101000a816200032f6200040a565b8160ff021916908360ff16021790620003476200046c565b5050505050505050505080600960016101000a81620003656200040a565b816001600160a01b0302191690836001600160a01b0316021790620003896200046c565b505050505050505050505050505062000597565b632a2a7adb598160e01b8152600481016020815285602082015260005b86811015620003d7578086015182820160400152602001620003ba565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b604081101562000467576000828201526020016200044e565b505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b6000815260206200044e565b8280620004c76200040a565b600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200051257805160ff191683800117856200050a6200046c565b505062000558565b82800160010185620005236200046c565b5050821562000558579182015b828111156200055857825182620005466200046c565b50509160200191906001019062000530565b50620005669291506200056a565b5090565b6200059491905b80821115620005665760008082620005886200046c565b50505060010162000571565b90565b6151ee80620005a76000396000f3fe608060405234801561001957600080610016614d0c565b50505b50600436106104055760003560e01c8063741853601161021e578063a9059cbb1161012e578063d8a1f76f116100c1578063e8e09b8b11610090578063e8e09b8b14610e23578063e90dd9e214610e58578063ec55688914610e60578063edef719a14610e68578063ee52a2f314610e9d57610405565b8063d8a1f76f14610d89578063dbf6334014610daf578063dd62ed3e14610db7578063e6203ed114610dee57610405565b8063c2bf3880116100fd578063c2bf388014610cd6578063c836fa0a14610d0b578063d37c4d8b14610d4c578063d67bdd2514610d8157610405565b8063a9059cbb14610c2f578063ace88afd14610c64578063af086c7e14610c9f578063bc67f83214610ca757610405565b80639324cac7116101b1578063987757dd11610180578063987757dd14610b745780639cbdaeb614610b9a5780639f76980714610ba2578063a311c7c214610bd1578063a5fdc5de14610c0057610405565b80639324cac714610b2d57806395d89b4114610b3557806397107d6d14610b3d5780639741fb2214610b6c57610405565b8063899ffef4116101ed578063899ffef414610aa85780638a29001414610ab05780638da5cb5b14610ad657806391e56b6814610ade57610405565b80637418536014610a4c57806379ba509714610a54578063835e119c14610a5c57806383d625d414610a8257610405565b80632c955fa7116103195780634e99bda9116102ac5780636ac0bf9c1161027b5780636ac0bf9c146109095780636c00f310146109385780636f01a9861461098757806370a08231146109c257806372cb051f146109f157610405565b80634e99bda91461087d57806353a47bb7146108855780635af090ef1461088d578063666ed4f1146108d457610405565b8063313ce567116102e8578063313ce567146107fa578063320223db1461080257806332608039146108315780633e89b9e51461085757610405565b80632c955fa71461072e5780632d3169eb1461075d5780632e0f26251461079557806330ead760146107b357610405565b80631627540c1161039c5780631fce304d1161036b5780631fce304d1461069357806323b872dd146106b9578063295da87d146106f85780632a9053181461071e5780632af64bd31461072657610405565b80631627540c1461062557806316b2213f1461065457806318160ddd14610683578063188214001461068b57610405565b80630e30963c116103d85780630e30963c146105405780631137aedf146105995780631249c58b146105ec578063131b0ae7146105f457610405565b806304f3bcec1461041357806305b3c1c91461043757806306fdde0314610478578063095ea7b3146104f7575b600080610410614d0c565b50505b61041b610ecf565b6040516001600160a01b03909116815260200160405180910390f35b6104666004803603602081101561045657600080610453614d0c565b50505b50356001600160a01b0316610eee565b60405190815260200160405180910390f35b610480610fad565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156104bc5780820151838201526020016104a4565b50505050905090810190601f1680156104e95780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61052c6004803603604081101561051657600080610513614d0c565b50505b506001600160a01b038135169060200135611066565b604051901515815260200160405180910390f35b6105786004803603608081101561055f5760008061055c614d0c565b50505b5080359060208101359060408101359060600135611164565b6040519182526001600160a01b031660208201526040908101905180910390f35b6105c8600480360360208110156105b8576000806105b5614d0c565b50505b50356001600160a01b0316611178565b60405180848152602001838152602001828152602001935050505060405180910390f35b61052c611252565b6106236004803603602081101561061357600080610610614d0c565b50505b50356001600160a01b031661125f565b005b6106236004803603602081101561064457600080610641614d0c565b50505b50356001600160a01b031661129d565b6104666004803603602081101561067357600080610670614d0c565b50505b50356001600160a01b0316611317565b61046661136a565b610480611377565b61052c600480360360208110156106b2576000806106af614d0c565b50505b50356113ae565b61052c600480360360608110156106d8576000806106d5614d0c565b50505b506001600160a01b03813581169160208101359091169060400135611493565b6106236004803603602081101561071757600080610714614d0c565b50505b50356114df565b6104806115aa565b61052c6115c7565b6106236004803603602081101561074d5760008061074a614d0c565b50505b50356001600160a01b0316611756565b6106236004803603608081101561077c57600080610779614d0c565b50505b50803590602081013590604081013590606001356117dc565b61079d611961565b60405160ff909116815260200160405180910390f35b610466600480360360a08110156107d2576000806107cf614d0c565b50505b508035906020810135906040810135906001600160a01b036060820135169060800135611966565b61079d611ae7565b610623600480360360208110156108215760008061081e614d0c565b50505b50356001600160a01b0316611b00565b61041b600480360360208110156108505760008061084d614d0c565b50505b5035611b33565b6104666004803603602081101561087657600080610873614d0c565b50505b5035611b7e565b61052c611bd2565b61041b611c7a565b610466600480360360a08110156108ac576000806108a9614d0c565b50505b508035906020810135906040810135906001600160a01b036060820135169060800135611c86565b610623600480360360408110156108f3576000806108f0614d0c565b50505b506001600160a01b038135169060200135611c99565b6104666004803603602081101561092857600080610925614d0c565b50505b50356001600160a01b0316611caf565b610623600480360360c081101561095757600080610954614d0c565b50505b506001600160a01b03813581169160208101359160408201359160608101359160808201359160a0013516611e49565b610623600480360360608110156109a6576000806109a3614d0c565b50505b506001600160a01b038135169060208101359060400135611fee565b610466600480360360208110156109e1576000806109de614d0c565b50505b50356001600160a01b0316612171565b6109f96121d7565b60405160208082528190810183818151815260200191508051906020019060200280838360005b83811015610a38578082015183820152602001610a20565b505050509050019250505060405180910390f35b610623612332565b610623612562565b61041b60048036036020811015610a7b57600080610a78614d0c565b50505b50356126e5565b61046660048036036020811015610aa157600080610a9e614d0c565b50505b5035612730565b6109f9612784565b61062360048036036020811015610acf57600080610acc614d0c565b50505b5035612804565b61041b612836565b610466600480360360c0811015610afd57600080610afa614d0c565b50505b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a00135612841565b61046661298b565b610480612996565b61062360048036036020811015610b5c57600080610b59614d0c565b50505b50356001600160a01b0316612a38565b610623612ab3565b6105c860048036036020811015610b9357600080610b90614d0c565b50505b5035612b76565b61041b612c33565b61062360048036036020811015610bc157600080610bbe614d0c565b50505b50356001600160a01b0316612c3f565b61046660048036036020811015610bf057600080610bed614d0c565b50505b50356001600160a01b0316612c83565b61046660048036036020811015610c1f57600080610c1c614d0c565b50505b50356001600160a01b0316612cd6565b61052c60048036036040811015610c4e57600080610c4b614d0c565b50505b506001600160a01b038135169060200135612d29565b61062360048036036060811015610c8357600080610c80614d0c565b50505b506001600160a01b038135169060208101359060400135612d91565b610623612e0e565b61062360048036036020811015610cc657600080610cc3614d0c565b50505b50356001600160a01b0316612e40565b61062360048036036040811015610cf557600080610cf2614d0c565b50505b506001600160a01b038135169060200135612e56565b61046660048036036080811015610d2a57600080610d27614d0c565b50505b506001600160a01b038135169060208101359060408101359060600135612f23565b61046660048036036040811015610d6b57600080610d68614d0c565b50505b506001600160a01b03813516906020013561306e565b61041b613134565b61062360048036036020811015610da857600080610da5614d0c565b50505b5035613140565b61046661320e565b61046660048036036040811015610dd657600080610dd3614d0c565b50505b506001600160a01b038135811691602001351661324b565b61052c60048036036040811015610e0d57600080610e0a614d0c565b50505b506001600160a01b0381351690602001356132b9565b61062360048036036040811015610e4257600080610e3f614d0c565b50505b506001600160a01b0381351690602001356132c3565b61041b6132f6565b61041b613302565b61062360048036036040811015610e8757600080610e84614d0c565b50505b506001600160a01b03813516906020013561330e565b61046660048036036060811015610ebc57600080610eb9614d0c565b50505b50803590602081013590604001356134d4565b60016009610edb614d77565b906101000a90046001600160a01b031681565b6000610ef8613672565b6001600160a01b03166305b3c1c9836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b158015610f5657600080610f53614d0c565b50505b505a610f60614e1e565b5050505050158015610f7f573d6000803e3d6000610f7c614d0c565b50505b505050506040513d6020811015610f9e57600080610f9b614d0c565b50505b81019080805195945050505050565b600680610fb8614d77565b600181600116156101000203166002900480601f016020809104026020016040519081016040528181529190602083018280610ff2614d77565b6001816001161561010002031660029004801561105e5780601f1061102c57610100808361101e614d77565b04028352916020019161105e565b820191906000526020600020905b81611043614d77565b8152906001019060200180831161103a57829003601f168201915b505050505081565b600061107061368b565b600080600461107d614d77565b906101000a90046001600160a01b03169050600560009061109c614d77565b906101000a90046001600160a01b03166001600160a01b031663da46098c8286866040516001600160e01b031960e086901b1681526001600160a01b03938416600482015291909216602482015260448101919091526064016000604051808303816000878061110a614dd2565b15801561111f5760008061111c614d0c565b50505b505a611129614f09565b505050505050158015611149573d6000803e3d6000611146614d0c565b50505b50505050611158818585613761565b60019150505b92915050565b60008061116f613844565b94509492505050565b6000806000611185613672565b6001600160a01b0316631137aedf856040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160606040518083038186806111ce614dd2565b1580156111e3576000806111e0614d0c565b50505b505a6111ed614e1e565b505050505015801561120c573d6000803e3d6000611209614d0c565b50505b505050506040513d606081101561122b57600080611228614d0c565b50505b81019080805192919060200180519291906020018051949993985093965091945050505050565b600061125c613844565b90565b611267613896565b806003600181611275614d77565b816001600160a01b0302191690836001600160a01b0316021790611297614fcf565b50505050565b6112a5613896565b80600180806112b2614d77565b816001600160a01b0302191690836001600160a01b03160217906112d4614fcf565b5050507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22816040516001600160a01b03909116815260200160405180910390a150565b6000611321613672565b6001600160a01b03166316b2213f836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b6008611374614d77565b81565b60405160408082019052601781527f53796e746865746978204e6574776f726b20546f6b656e000000000000000000602082015281565b6000806113b961390e565b6001600160a01b031663059c29ec600060046113d3614d77565b906101000a90046001600160a01b0316856040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303818680611423614dd2565b15801561143857600080611435614d0c565b50505b505a611442614e1e565b5050505050158015611461573d6000803e3d600061145e614d0c565b50505b505050506040513d60208110156114805760008061147d614d0c565b50505b8101908080519390931195945050505050565b600061149d61368b565b6114a5613925565b6114af848361399b565b506114d7600060046114bf614d77565b906101000a90046001600160a01b0316858585613cb0565b949350505050565b6114e7613de2565b6114ef61368b565b6114f7613672565b6001600160a01b031663b06e8c6560006004611511614d77565b906101000a90046001600160a01b0316836040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780611563614dd2565b15801561157857600080611575614d0c565b50505b505a611582614f09565b5050505050501580156115a2573d6000803e3d600061159f614d0c565b50505b505050505b50565b6040516040808201905260038152620a69cb60eb1b602082015281565b600060606115d3612784565b905060005b815181101561174d5760008282815181106115ef57fe5b60200260200101516000818152600a60205290915060409020600090611613614d77565b6001600160a01b036101009290920a90041660016009611631614d77565b906101000a90046001600160a01b03166001600160a01b03166321f8a721836040516001600160e01b031960e084901b16815260048101919091526024016020604051808303818680611682614dd2565b15801561169757600080611694614d0c565b50505b505a6116a1614e1e565b50505050501580156116c0573d6000803e3d60006116bd614d0c565b50505b505050506040513d60208110156116df576000806116dc614d0c565b50505b8101908080516001600160a01b031693909314159250829150611733905057506000818152600a60205260408120600090611718614d77565b906101000a90046001600160a01b03166001600160a01b0316145b15611744576000935050505061125c565b506001016115d8565b50600191505090565b61175e613de2565b61176661368b565b61176e613672565b6001600160a01b0316632b3f41aa8260006004611789614d77565b906101000a90046001600160a01b03166040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160006040518083038160008780611563614dd2565b6117e4613e1d565b600060026117f0614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff9784848460405160200180848152602001838152602001828152602001935050505060405160208183030381529060405260026040518060316150c1823960310190506040518091039020886000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156118cc5780820151838201526020016118b4565b50505050905090810190601f1680156118f95780820380516001836020036101000a031916815260200191505b5097505050505050505060006040518083038160008780611918614dd2565b15801561192d5760008061192a614d0c565b50505b505a611937614f09565b505050505050158015611957573d6000803e3d6000611954614d0c565b50505b5050505050505050565b601281565b600085846119748282613e97565b61197c61368b565b61198461390e565b6001600160a01b0316634f8633d26000600461199e614d77565b906101000a90046001600160a01b031660046000906119bb614d77565b906101000a90046001600160a01b03168b8b8b60046000906119db614d77565b906101000a90046001600160a01b031660008d8d6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e482015261010481019190915261012401604080518083038160008780611a6a614dd2565b158015611a7f57600080611a7c614d0c565b50505b505a611a89614f09565b505050505050158015611aa9573d6000803e3d6000611aa6614d0c565b50505b505050506040513d6040811015611ac857600080611ac5614d0c565b50505b810190808051929190602001805150929b9a5050505050505050505050565b60006009611af3614d77565b906101000a900460ff1681565b611b08613de2565b611b1061368b565b611b18613672565b6001600160a01b031663fd864ccf8260006004611789614d77565b6000611b3d613672565b6001600160a01b03166332608039836040516001600160e01b031960e084901b16815260048101919091526024016020604051808303818680610f41614dd2565b6000611b88613672565b6001600160a01b0316637b1001b78360016040516001600160e01b031960e085901b1681526004810192909252151560248201526044016020604051808303818680610f41614dd2565b6000611bdc613672565b6001600160a01b0316634e99bda96040518163ffffffff1660e01b81526004016020604051808303818680611c0f614dd2565b158015611c2457600080611c21614d0c565b50505b505a611c2e614e1e565b5050505050158015611c4d573d6000803e3d6000611c4a614d0c565b50505b505050506040513d6020811015611c6c57600080611c69614d0c565b50505b810190808051935050505090565b60006001610edb614d77565b6000611c90613844565b95945050505050565b611ca1613f21565b611cab8282613f9b565b5050565b6000611cb9613672565b6001600160a01b0316636bed04158360006005611cd4614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231866040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680611d2d614dd2565b158015611d4257600080611d3f614d0c565b50505b505a611d4c614e1e565b5050505050158015611d6b573d6000803e3d6000611d68614d0c565b50505b505050506040513d6020811015611d8a57600080611d87614d0c565b50505b81019080805192506040915050516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160408051808303818680611dd3614dd2565b158015611de857600080611de5614d0c565b50505b505a611df2614e1e565b5050505050158015611e11573d6000803e3d6000611e0e614d0c565b50505b505050506040513d6040811015611e3057600080611e2d614d0c565b50505b8101908080519291906020018051509295945050505050565b611e51613e1d565b60006002611e5d614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff9786868686866040516020810195909552604080860194909452606085019290925260808401526001600160a01b031660a083015260c09091019051602081830303815290604052600260405180603e6150f28239603e0190506040518091039020611ee58b61419d565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015611f58578082015183820152602001611f40565b50505050905090810190601f168015611f855780820380516001836020036101000a031916815260200191505b5097505050505050505060006040518083038160008780611fa4614dd2565b158015611fb957600080611fb6614d0c565b50505b505a611fc3614f09565b505050505050158015611954573d6000803e3d6000611fe0614d0c565b505050505050505050505050565b611ff6613e1d565b60006002612002614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff978383604051602001808381526020018281526020019250505060405160208183030381529060405260026040518060276151a682396027019050604051809103902061206b8861419d565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156120de5780820151838201526020016120c6565b50505050905090810190601f16801561210b5780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303816000878061212a614dd2565b15801561213f5760008061213c614d0c565b50505b505a612149614f09565b50505050505015801561159f573d6000803e3d6000612166614d0c565b505050505050505050565b600080600561217e614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b60606121e1613672565b6001600160a01b03166372cb051f6040518163ffffffff1660e01b81526004016000604051808303818680612214614dd2565b15801561222957600080612226614d0c565b50505b505a612233614e1e565b5050505050158015612252573d6000803e3d600061224f614d0c565b50505b505050506040513d6000823e601f3d908101601f19168201604052602081101561228457600080612281614d0c565b50505b81019080805160405193929190846401000000008211156122ad576000806122aa614d0c565b50505b9083019060208201858111156122cb576000806122c8614d0c565b50505b82518660208202830111640100000000821117156122f1576000806122ee614d0c565b50505b825250602001908051906020019060200280838360005b83811015612320578082015183820152602001612308565b50505050905001604052505050905090565b606061233c612784565b905060005b8151811015611cab57600082828151811061235857fe5b60200260200101519050600060016009612370614d77565b906101000a90046001600160a01b03166001600160a01b031663dacb2d0183846040517f5265736f6c766572206d697373696e67207461726765743a2000000000000000602082015260398101919091526059016040516020818303038152906040526040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561242557808201518382015260200161240d565b50505050905090810190601f1680156124525780820380516001836020036101000a031916815260200191505b509350505050602060405180830381868061246b614dd2565b1580156124805760008061247d614d0c565b50505b505a61248a614e1e565b50505050501580156124a9573d6000803e3d60006124a6614d0c565b50505b505050506040513d60208110156124c8576000806124c5614d0c565b50505b8101908080516000868152600a602052909450849350604092509050206001816124f0614d77565b816001600160a01b0302191690836001600160a01b0316021790612512614fcf565b5050507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa6882826040519182526001600160a01b031660208201526040908101905180910390a15050600101612341565b6000600161256e614d77565b906101000a90046001600160a01b03166001600160a01b03165a61259061501d565b6001600160a01b0316146125de5760405162461bcd60e51b815260040180806020018281038252603581526020018061506460359139604001915050604051809103906125db614d0c565b50505b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c60008061260a614d77565b906101000a90046001600160a01b03166001600090612627614d77565b906101000a90046001600160a01b03166040516001600160a01b039283168152911660208201526040908101905180910390a160006001612666614d77565b906101000a90046001600160a01b03166000806101000a81612686614d77565b816001600160a01b0302191690836001600160a01b03160217906126a8614fcf565b5050506000600160006101000a816126be614d77565b816001600160a01b0302191690836001600160a01b03160217906126e0614fcf565b505050565b60006126ef613672565b6001600160a01b031663835e119c836040516001600160e01b031960e084901b16815260048101919091526024016020604051808303818680610f41614dd2565b600061273a613672565b6001600160a01b0316637b1001b78360006040516001600160e01b031960e085901b1681526004810192909252151560248201526044016020604051808303818680610f41614dd2565b60608061278f6141a9565b9050606060016040519080825280602002602001820160405280156127be578160200160208202803883390190505b5090507453796e746865746978427269646765546f4261736560581b816000815181106127e757fe5b6020026020010181815250506127fd82826142a9565b9250505090565b61280c613de2565b61281461368b565b61281c613672565b6001600160a01b031663042e068860006004611511614d77565b600080610edb614d77565b6000858461284f8282613e97565b61285761368b565b61285f61390e565b6001600160a01b0316634f8633d28a6000600461287a614d77565b906101000a90046001600160a01b03168b8b8b8f60008d8d6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e48201526101048101919091526101240160408051808303816000878061290d614dd2565b1580156129225760008061291f614d0c565b50505b505a61292c614f09565b50505050505015801561294c573d6000803e3d6000612949614d0c565b50505b505050506040513d604081101561296b57600080612968614d0c565b50505b810190808051929190602001805150929c9b505050505050505050505050565b631cd554d160e21b81565b6007806129a1614d77565b600181600116156101000203166002900480601f0160208091040260200160405190810160405281815291906020830182806129db614d77565b6001816001161561010002031660029004801561105e5780601f10612a0757610100808361101e614d77565b820191906000526020600020905b81612a1e614d77565b81529060010190602001808311612a155750859350505050565b612a40613896565b806002600181612a4e614d77565b816001600160a01b0302191690836001600160a01b0316021790612a70614fcf565b5050507ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e816040516001600160a01b03909116815260200160405180910390a150565b612abb613de2565b612ac361368b565b612acb613672565b6001600160a01b031663497d704a60006004612ae5614d77565b906101000a90046001600160a01b03166040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160006040518083038160008780612b31614dd2565b158015612b4657600080612b43614d0c565b50505b505a612b50614f09565b505050505050158015611297573d6000803e3d6000612b6d614d0c565b5050505050505b565b6000806000612b8361368b565b612b8b61390e565b6001600160a01b0316631b16802c60006004612ba5614d77565b906101000a90046001600160a01b0316866040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160606040518083038160008780612bf7614dd2565b158015612c0c57600080612c09614d0c565b50505b505a612c16614f09565b50505050505015801561120c573d6000803e3d6000611209614d0c565b60006003610edb614d77565b612c47614365565b806005600181612c55614d77565b816001600160a01b0302191690836001600160a01b0316021790612c77614fcf565b5050506115a7816144f0565b6000612c8d613672565b6001600160a01b031663a311c7c2836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b6000612ce0613672565b6001600160a01b031663a5fdc5de836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b6000612d3361368b565b612d3b613925565b612d6060006004612d4a614d77565b906101000a90046001600160a01b03168361399b565b50612d8760006004612d70614d77565b906101000a90046001600160a01b03168484614638565b5060019392505050565b612d99613e1d565b60006002612da5614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff9783836040516020018083815260200182815260200192505050604051602081830303815290604052600260405180602861509982396028019050604051809103902061206b8861419d565b612e16613de2565b612e1e61368b565b612e26613672565b6001600160a01b031663c897713260006004612ae5614d77565b612e48614645565b806004600181611275614d77565b612e5e613de2565b612e6661368b565b612e6e613672565b6001600160a01b0316639a5154b48360006004612e89614d77565b906101000a90046001600160a01b0316846040516001600160e01b031960e086901b1681526001600160a01b039384166004820152919092166024820152604481019190915260640160006040518083038160008780612ee7614dd2565b158015612efc57600080612ef9614d0c565b50505b505a612f06614f09565b505050505050158015612b6d573d6000803e3d6000611957614d0c565b60008382612f318282613e97565b612f3961368b565b612f4161390e565b6001600160a01b0316634f8633d28860006004612f5c614d77565b906101000a90046001600160a01b03168989898d60008f6000801b6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e482015261010481019190915261012401604080518083038160008780612ff2614dd2565b15801561300757600080613004614d0c565b50505b505a613011614f09565b505050505050158015613031573d6000803e3d600061302e614d0c565b50505b505050506040513d60408110156130505760008061304d614d0c565b50505b810190808051929190602001805150929a9950505050505050505050565b6000613078613672565b6001600160a01b031663d37c4d8b84846040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160206040518083038186806130c7614dd2565b1580156130dc576000806130d9614d0c565b50505b505a6130e6614e1e565b5050505050158015613105573d6000803e3d6000613102614d0c565b50505b505050506040513d602081101561312457600080613121614d0c565b50505b8101908080519695505050505050565b60006004610edb614d77565b613148613f21565b6000613152614712565b905061315e8183613f9b565b806001600160a01b03166359974e38836040516001600160e01b031960e084901b1681526004810191909152602401602060405180830381600087806131a2614dd2565b1580156131b7576000806131b4614d0c565b50505b505a6131c1614f09565b5050505050501580156131e1573d6000803e3d60006131de614d0c565b50505b505050506040513d6020811015613200576000806131fd614d0c565b50505b810190808051505050505050565b6000613218613672565b6001600160a01b031663dbf633406040518163ffffffff1660e01b81526004016020604051808303818680611c0f614dd2565b6000806005613258614d77565b906101000a90046001600160a01b03166001600160a01b031663dd62ed3e84846040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186806130c7614dd2565b600061115e613844565b6132cb613de2565b6132d361368b565b6132db613672565b6001600160a01b03166344ec6b628360006004612e89614d77565b60006005610edb614d77565b60006002610edb614d77565b613316613f21565b61331e613925565b6000600561332a614d77565b6001600160a01b036101009290920a90041663b46310f68361341f8460006005613352614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231886040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186806133ab614dd2565b1580156133c0576000806133bd614d0c565b50505b505a6133ca614e1e565b50505050501580156133e9573d6000803e3d60006133e6614d0c565b50505b505050506040513d602081101561340857600080613405614d0c565b50505b8101908080519392505063ffffffff614733169050565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780613460614dd2565b15801561347557600080613472614d0c565b50505b505a61347f614f09565b50505050505015801561349f573d6000803e3d600061349c614d0c565b50505b505050506134af82600083614798565b6134c98160086134bd614d77565b9063ffffffff61473316565b8060086115a2614fcf565b600083826134e28282613e97565b6134ea61368b565b6134f261390e565b6001600160a01b0316634f8633d26000600461350c614d77565b906101000a90046001600160a01b03166004600090613529614d77565b906101000a90046001600160a01b03168989896004600090613549614d77565b906101000a90046001600160a01b031660006004600090613568614d77565b906101000a90046001600160a01b03166000801b6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e4820152610104810191909152610124016040805180830381600087806135f7614dd2565b15801561360c57600080613609614d0c565b50505b505a613616614f09565b505050505050158015613636573d6000803e3d6000613633614d0c565b50505b505050506040513d604081101561365557600080613652614d0c565b50505b810190808051929190602001805150929998505050505050505050565b60006136866524b9b9bab2b960d11b614805565b905090565b60006002613697614d77565b906101000a90046001600160a01b03166001600160a01b03165a6136b961501d565b6001600160a01b0316141580156137055750600060036136d7614d77565b906101000a90046001600160a01b03166001600160a01b03165a6136f961501d565b6001600160a01b031614155b801561374657505a61371561501d565b6001600160a01b03166000600461372a614d77565b906101000a90046001600160a01b03166001600160a01b031614155b15612b74575a61375461501d565b60046001816126be614d77565b6000600261376d614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff97826040516020018082815260200191505060405160208183030381529060405260036040518060216151858239602101905060405180910390206137ce8861419d565b6137d78861419d565b60006040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018481526020018360001b8152602001828103825288818151815260200191508051602090910190808383600083156120de5780820151838201526020016120c6565b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f742062652072756e206f6e2074686973206c617965720000000000604482015260640160405180910390611cab614d0c565b6000806138a1614d77565b906101000a90046001600160a01b03166001600160a01b03165a6138c361501d565b6001600160a01b031614612b745760405162461bcd60e51b815260040180806020018281038252602f815260200180615156602f913960400191505060405180910390611cab614d0c565b60006136866822bc31b430b733b2b960b91b614805565b61392d614906565b6001600160a01b031663086dabd16040518163ffffffff1660e01b81526004016000604051808303818680613960614dd2565b15801561397557600080613972614d0c565b50505b505a61397f614e1e565b5050505050158015611297573d6000803e3d6000612b6d614d0c565b6000806139a6614920565b6001600160a01b0316638b3f8088856040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401604080518083038186806139ee614dd2565b158015613a0357600080613a00614d0c565b50505b505a613a0d614e1e565b5050505050158015613a2c573d6000803e3d6000613a29614d0c565b50505b505050506040513d6040811015613a4b57600080613a48614d0c565b50505b8101908080519291906020018051509293505082159150611158905057600080613a73613672565b6001600160a01b0316636bed04158760006005613a8e614d77565b906101000a90046001600160a01b03166001600160a01b03166370a082318a6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680613ae7614dd2565b158015613afc57600080613af9614d0c565b50505b505a613b06614e1e565b5050505050158015613b25573d6000803e3d6000613b22614d0c565b50505b505050506040513d6020811015613b4457600080613b41614d0c565b50505b81019080805192506040915050516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160408051808303818680613b8d614dd2565b158015613ba257600080613b9f614d0c565b50505b505a613bac614e1e565b5050505050158015613bcb573d6000803e3d6000613bc8614d0c565b50505b505050506040513d6040811015613bea57600080613be7614d0c565b50505b810190808051929190602001805193955092935050505081851115613c495760405162461bcd60e51b81526004018080602001828103825260268152602001806151306026913960400191505060405180910390613c46614d0c565b50505b8015613ca45760405162461bcd60e51b815260206004820152601e60248201527f412073796e7468206f7220534e58207261746520697320696e76616c69640000604482015260640160405180910390613ca1614d0c565b50505b50600195945050505050565b6000806005613cbd614d77565b6001600160a01b036101009290920a90041663da46098c8587613d478660006005613ce6614d77565b906101000a90046001600160a01b03166001600160a01b031663dd62ed3e8b8d6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186806133ab614dd2565b6040516001600160e01b031960e086901b1681526001600160a01b039384166004820152919092166024820152604481019190915260640160006040518083038160008780613d94614dd2565b158015613da957600080613da6614d0c565b50505b505a613db3614f09565b505050505050158015613dd3573d6000803e3d6000613dd0614d0c565b50505b50505050611c9084848461493c565b613dea614906565b6001600160a01b0316637c3125416040518163ffffffff1660e01b81526004016000604051808303818680613960614dd2565b613e2561390e565b6001600160a01b03165a613e3761501d565b6001600160a01b031614612b745760405162461bcd60e51b815260206004820152601e60248201527f4f6e6c792045786368616e6765722063616e20696e766f6b6520746869730000604482015260640160405180910390611cab614d0c565b613e9f614906565b6001600160a01b0316631ce00ba283836040516001600160e01b031960e085901b168152600481019290925260248201526044016000604051808303818680613ee6614dd2565b158015613efb57600080613ef8614d0c565b50505b505a613f05614e1e565b5050505050158015612b6d573d6000803e3d6000611957614d0c565b613f29614c80565b6001600160a01b03165a613f3b61501d565b6001600160a01b031614612b745760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c7920626520696e766f6b656420627920627269646765000000604482015260640160405180910390611cab614d0c565b60006005613fa7614d77565b6001600160a01b036101009290920a90041663b46310f68361409c8460006005613fcf614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231886040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680614028614dd2565b15801561403d5760008061403a614d0c565b50505b505a614047614e1e565b5050505050158015614066573d6000803e3d6000614063614d0c565b50505b505050506040513d602081101561408557600080614082614d0c565b50505b8101908080519392505063ffffffff614ca3169050565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087806140dd614dd2565b1580156140f2576000806140ef614d0c565b50505b505a6140fc614f09565b50505050505015801561411c573d6000803e3d6000614119614d0c565b50505b505050506141835a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b604081101561417957600082820152602001614162565b5050508383614798565b6134c9816008614191614d77565b9063ffffffff614ca316565b6001600160a01b031690565b606060056040519080825280602002602001820160405280156141d6578160200160208202803883390190505b5090506d53796e746865746978537461746560901b816000815181106141f857fe5b6020026020010181815250506b53797374656d53746174757360a01b8160018151811061422157fe5b6020026020010181815250506822bc31b430b733b2b960b91b8160028151811061424757fe5b6020026020010181815250506524b9b9bab2b960d11b8160038151811061426a57fe5b602002602001018181525050722932bbb0b93239a234b9ba3934b13aba34b7b760691b8160048151811061429a57fe5b60200260200101818152505090565b606081518351016040519080825280602002602001820160405280156142d9578160200160208202803883390190505b50905060005b835181101561431b578381815181106142f457fe5b602002602001015182828151811061430857fe5b60209081029190910101526001016142df565b5060005b825181101561435e5782818151811061433457fe5b602002602001015182828651018151811061434b57fe5b602090810291909101015260010161431f565b5092915050565b60006002614371614d77565b906101000a90046001600160a01b03166001600160a01b03165a61439361501d565b6001600160a01b0316141580156143df5750600060036143b1614d77565b906101000a90046001600160a01b03166001600160a01b03165a6143d361501d565b6001600160a01b031614155b801561442057505a6143ef61501d565b6001600160a01b031660006004614404614d77565b906101000a90046001600160a01b03166001600160a01b031614155b15614461575a61442e61501d565b600460018161443b614d77565b816001600160a01b0302191690836001600160a01b031602179061445d614fcf565b5050505b60008061446c614d77565b6001600160a01b036101009290920a9004166000600461448a614d77565b906101000a90046001600160a01b03166001600160a01b031614612b745760405162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015260640160405180910390611cab614d0c565b600060026144fc614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff97826040516001600160a01b0390911660208201526040908101905160208183030381529060405260016040517f546f6b656e5374617465557064617465642861646472657373290000000000008152601a01604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156145ec5780820151838201526020016145d4565b50505050905090810190601f1680156146195780820380516001836020036101000a031916815260200191505b5097505050505050505060006040518083038160008780611563614dd2565b60006114d784848461493c565b60006002614651614d77565b906101000a90046001600160a01b03166001600160a01b03165a61467361501d565b6001600160a01b031614806146bc57506000600361468f614d77565b906101000a90046001600160a01b03166001600160a01b03165a6146b161501d565b6001600160a01b0316145b612b745760405162461bcd60e51b815260206004820152601760248201527f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000604482015260640160405180910390611cab614d0c565b6000613686722932bbb0b93239a234b9ba3934b13aba34b7b760691b614805565b6000828211156147925760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f77000060448201526064016040518091039061478f614d0c565b50505b50900390565b600060026147a4614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff97826040516020018082815260200191505060405160208183030381529060405260036040518060216151cd8239602101905060405180910390206137ce8861419d565b6000818152600a602052806040812060009061481f614d77565b6001600160a01b036101009290920a90041690508015158360405170026b4b9b9b4b7339030b2323932b9b99d1607d1b602082015260318101919091526051016040516020818303038152906040529061435e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156148bc5780820151838201526020016148a4565b50505050905090810190601f1680156148e95780820380516001836020036101000a031916815260200191505b5092505050604051809103906148fd614d0c565b50505092915050565b60006136866b53797374656d53746174757360a01b614805565b60006136866d53796e746865746978537461746560901b614805565b60006001600160a01b038316158015906149c057505a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b60408110156149a757600082820152602001614990565b5050506001600160a01b0316836001600160a01b031614155b80156149f95750600060026149d3614d77565b906101000a90046001600160a01b03166001600160a01b0316836001600160a01b031614155b614a525760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220746f2074686973206164647265737300604482015260640160405180910390614a4f614d0c565b50505b60006005614a5e614d77565b6001600160a01b036101009290920a90041663b46310f685614adf8560006005614a86614d77565b906101000a90046001600160a01b03166001600160a01b03166370a082318a6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186806133ab614dd2565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780614b20614dd2565b158015614b3557600080614b32614d0c565b50505b505a614b3f614f09565b505050505050158015614b5f573d6000803e3d6000614b5c614d0c565b50505b505050506005600090614b70614d77565b6001600160a01b036101009290920a90041663b46310f684614bf18560006005614b98614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231896040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680614028614dd2565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780614c32614dd2565b158015614c4757600080614c44614d0c565b50505b505a614c51614f09565b505050505050158015614c71573d6000803e3d6000614c6e614d0c565b50505b50505050612d87848484614798565b60006136867453796e746865746978427269646765546f4261736560581b614805565b600082820183811015614d055760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640160405180910390614d02614d0c565b50505b9392505050565b632a2a7adb598160e01b8152600481016020815285602082015260005b86811015614d44578086015182820160400152602001614d29565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b60408110156126e057600082820152602001614dbb565b638435035b598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b80516000825293506020614dbb565b638540661f598160e01b8152614e4f565b808083111561115e575090919050565b808083101561115e575090919050565b836004820152846024820152606060448201528660648201526084810160005b88811015614e87578088015182820152602001614e6f565b506060828960a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8b8b82606087013350600060045af15059614edc8d3d614e3f565b8c01614ee88187614e2f565b5b82811015614efd5760008152602001614ee9565b50929c50505050505050565b6385979f76598160e01b8152836004820152846024820152606060448201528760648201526084810160005b89811015614f4d578089015182820152602001614f35565b506060828a60a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8c8c82606087013350600060045af15059614fa28e3d614e3f565b8d01614fae8187614e2f565b5b82811015614fc35760008152602001614faf565b50929d50505050505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b600081526020614dbb565b6373509064598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b80516000825293506020614dbb56fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e65727368697045786368616e67655265636c61696d28616464726573732c627974657333322c75696e743235362945786368616e6765547261636b696e6728627974657333322c627974657333322c75696e743235362c75696e743235362953796e746845786368616e676528616464726573732c627974657333322c75696e743235362c627974657333322c75696e743235362c616464726573732943616e6e6f74207472616e73666572207374616b6564206f7220657363726f77656420534e584f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e417070726f76616c28616464726573732c616464726573732c75696e743235362945786368616e676552656261746528616464726573732c627974657333322c75696e74323536295472616e7366657228616464726573732c616464726573732c75696e7432353629", + "bytecode": "60806040523480156200001157600080fd5b50604051620042f7380380620042f7833981810160405260a08110156200003757600080fd5b508051602080830151604080850151606086015160809096015182518084018452601781527f53796e746865746978204e6574776f726b20546f6b656e00000000000000000081870152835180850190945260038452620a69cb60eb1b958401959095529495929490939091869186918691869186918291879187918660128986816001600160a01b03811662000115576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1506000546001600160a01b0316620001c0576040805162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b604482015290519081900360640190fd5b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9181900360200190a150600480546001600160a01b0319166001600160a01b038816179055845162000242906005906020880190620002ab565b50835162000258906006906020870190620002ab565b50506007919091556008805460ff191660ff90921691909117610100600160a81b0319166101006001600160a01b0397909716969096029590951790945550620003509c50505050505050505050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002ee57805160ff19168380011785556200031e565b828001600101855582156200031e579182015b828111156200031e57825182559160200191906001019062000301565b506200032c92915062000330565b5090565b6200034d91905b808211156200032c576000815560010162000337565b90565b613f9780620003606000396000f3fe608060405234801561001057600080fd5b50600436106103f15760003560e01c80637418536011610215578063ace88afd11610125578063d8a1f76f116100b8578063e8e09b8b11610087578063e8e09b8b14610c94578063e90dd9e214610cc0578063ec55688914610cc8578063edef719a14610cd0578063ee52a2f314610cfc576103f1565b8063d8a1f76f14610c15578063dbf6334014610c32578063dd62ed3e14610c3a578063e6203ed114610c68576103f1565b8063c62e5df8116100f4578063c62e5df814610b7a578063c836fa0a14610ba9578063d37c4d8b14610be1578063d67bdd2514610c0d576103f1565b8063ace88afd14610aee578063af086c7e14610b20578063bc67f83214610b28578063c2bf388014610b4e576103f1565b80639324cac7116101a8578063987757dd11610177578063987757dd14610a335780639f76980714610a50578063a311c7c214610a76578063a5fdc5de14610a9c578063a9059cbb14610ac2576103f1565b80639324cac7146109f557806395d89b41146109fd57806397107d6d14610a055780639741fb2214610a2b576103f1565b8063899ffef4116101e4578063899ffef4146109825780638a2900141461098a5780638da5cb5b146109a757806391e56b68146109af576103f1565b8063741853601461093857806379ba509714610940578063835e119c1461094857806383d625d414610965576103f1565b80632c955fa7116103105780634e99bda9116102a35780636ac0bf9c116102725780636ac0bf9c1461081c5780636c00f310146108425780636f01a9861461088857806370a08231146108ba57806372cb051f146108e0576103f1565b80634e99bda9146107a257806353a47bb7146107aa5780635af090ef146107b2578063666ed4f1146107f0576103f1565b8063313ce567116102df578063313ce5671461073a578063320223db1461074257806332608039146107685780633e89b9e514610785576103f1565b80632c955fa7146106895780632d3169eb146106af5780632e0f2625146106de57806330ead760146106fc576103f1565b806316b2213f1161038857806323b872dd1161035757806323b872dd14610626578063295da87d1461065c5780632a905318146106795780632af64bd314610681576103f1565b806316b2213f146105d357806318160ddd146105f957806318821400146106015780631fce304d14610609576103f1565b80630e30963c116103c45780630e30963c1461050f5780631137aedf1461055f5780631249c58b146105a35780631627540c146105ab576103f1565b806304f3bcec146103f657806305b3c1c91461041a57806306fdde0314610452578063095ea7b3146104cf575b600080fd5b6103fe610d25565b604080516001600160a01b039092168252519081900360200190f35b6104406004803603602081101561043057600080fd5b50356001600160a01b0316610d39565b60408051918252519081900360200190f35b61045a610dca565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049457818101518382015260200161047c565b50505050905090810190601f1680156104c15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104fb600480360360408110156104e557600080fd5b506001600160a01b038135169060200135610e58565b604080519115158252519081900360200190f35b61053e6004803603608081101561052557600080fd5b5080359060208101359060408101359060600135610ef3565b604080519283526001600160a01b0390911660208301528051918290030190f35b6105856004803603602081101561057557600080fd5b50356001600160a01b0316610f07565b60408051938452602084019290925282820152519081900360600190f35b6104fb610fad565b6105d1600480360360208110156105c157600080fd5b50356001600160a01b0316610fba565b005b610440600480360360208110156105e957600080fd5b50356001600160a01b0316611016565b610440611075565b61045a61107b565b6104fb6004803603602081101561061f57600080fd5b50356110b4565b6104fb6004803603606081101561063c57600080fd5b506001600160a01b03813581169160208101359091169060400135611147565b6105d16004803603602081101561067257600080fd5b5035611184565b61045a61120e565b6104fb61122d565b6105d16004803603602081101561069f57600080fd5b50356001600160a01b031661133e565b6105d1600480360360808110156106c557600080fd5b50803590602081013590604081013590606001356113ad565b6106e66114f0565b6040805160ff9092168252519081900360200190f35b610440600480360360a081101561071257600080fd5b508035906020810135906040810135906001600160a01b0360608201351690608001356114f5565b6106e66115d3565b6105d16004803603602081101561075857600080fd5b50356001600160a01b03166115dc565b6103fe6004803603602081101561077e57600080fd5b503561164b565b6104406004803603602081101561079b57600080fd5b5035611698565b6104fb6116f2565b6103fe611765565b610440600480360360a08110156107c857600080fd5b508035906020810135906040810135906001600160a01b036060820135169060800135611774565b6105d16004803603604081101561080657600080fd5b506001600160a01b038135169060200135611787565b6104406004803603602081101561083257600080fd5b50356001600160a01b031661179d565b6105d1600480360360c081101561085857600080fd5b506001600160a01b03813581169160208101359160408201359160608101359160808201359160a001351661189f565b6105d16004803603606081101561089e57600080fd5b506001600160a01b0381351690602081013590604001356119fe565b610440600480360360208110156108d057600080fd5b50356001600160a01b0316611b3f565b6108e8611b92565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561092457818101518382015260200161090c565b505050509050019250505060405180910390f35b6105d1611ca2565b6105d1611e7b565b6103fe6004803603602081101561095e57600080fd5b5035611f37565b6104406004803603602081101561097b57600080fd5b5035611f84565b6108e8611fde565b6105d1600480360360208110156109a057600080fd5b5035612052565b6103fe6120bf565b610440600480360360c08110156109c557600080fd5b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a001356120ce565b6104406121b1565b61045a6121bc565b6105d160048036036020811015610a1b57600080fd5b50356001600160a01b0316612217565b6105d1612273565b61058560048036036020811015610a4957600080fd5b50356122f5565b6105d160048036036020811015610a6657600080fd5b50356001600160a01b0316612375565b61044060048036036020811015610a8c57600080fd5b50356001600160a01b03166123a1565b61044060048036036020811015610ab257600080fd5b50356001600160a01b0316612400565b6104fb60048036036040811015610ad857600080fd5b506001600160a01b03813516906020013561245f565b6105d160048036036060811015610b0457600080fd5b506001600160a01b03813516906020810135906040013561249f565b6105d16124ff565b6105d160048036036020811015610b3e57600080fd5b50356001600160a01b0316612566565b6105d160048036036040811015610b6457600080fd5b506001600160a01b038135169060200135612590565b61044060048036036080811015610b9057600080fd5b5080359060208101359060408101359060600135612622565b61044060048036036080811015610bbf57600080fd5b506001600160a01b03813516906020810135906040810135906060013561262c565b61044060048036036040811015610bf757600080fd5b506001600160a01b03813516906020013561270a565b6103fe6127a4565b6105d160048036036020811015610c2b57600080fd5b50356127b3565b610440612841565b61044060048036036040811015610c5057600080fd5b506001600160a01b0381358116916020013516612883565b6104fb60048036036040811015610c7e57600080fd5b506001600160a01b0381351690602001356128de565b6105d160048036036040811015610caa57600080fd5b506001600160a01b0381351690602001356129c1565b6103fe612a37565b6103fe612a46565b6105d160048036036040811015610ce657600080fd5b506001600160a01b038135169060200135612a55565b61044060048036036060811015610d1257600080fd5b5080359060208101359060400135612b8a565b60085461010090046001600160a01b031681565b6000610d43612c68565b6001600160a01b03166305b3c1c9836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b505afa158015610dac573d6000803e3d6000fd5b505050506040513d6020811015610dc257600080fd5b505192915050565b6005805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610e505780601f10610e2557610100808354040283529160200191610e50565b820191906000526020600020905b815481529060010190602001808311610e3357829003601f168201915b505050505081565b6000610e62612c81565b6003546004805460408051633691826360e21b81526001600160a01b03948516938101849052878516602482015260448101879052905192939091169163da46098c9160648082019260009290919082900301818387803b158015610ec657600080fd5b505af1158015610eda573d6000803e3d6000fd5b50505050610ee9818585612cc0565b5060019392505050565b600080610efe612d8a565b94509492505050565b6000806000610f14612c68565b6001600160a01b0316631137aedf856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060606040518083038186803b158015610f6957600080fd5b505afa158015610f7d573d6000803e3d6000fd5b505050506040513d6060811015610f9357600080fd5b508051602082015160409092015190969195509350915050565b6000610fb7612d8a565b90565b610fc2612dd7565b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b6000611020612c68565b6001600160a01b03166316b2213f836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b60075481565b6040518060400160405280601781526020017f53796e746865746978204e6574776f726b20546f6b656e00000000000000000081525081565b6000806110bf612e20565b600354604080516301670a7b60e21b81526001600160a01b039283166004820152602481018790529051929091169163059c29ec91604480820192602092909190829003018186803b15801561111457600080fd5b505afa158015611128573d6000803e3d6000fd5b505050506040513d602081101561113e57600080fd5b50511192915050565b6000611151612c81565b611159612e37565b6111638483612e8b565b5060035461117c906001600160a01b03168585856130bf565b949350505050565b61118c6131b7565b611194612c81565b61119c612c68565b6003546040805163b06e8c6560e01b81526001600160a01b039283166004820152602481018590529051929091169163b06e8c659160448082019260009290919082900301818387803b1580156111f257600080fd5b505af1158015611206573d6000803e3d6000fd5b505050505b50565b604051806040016040528060038152602001620a69cb60eb1b81525081565b60006060611239611fde565b905060005b815181101561133557600082828151811061125557fe5b6020908102919091018101516000818152600983526040908190205460085482516321f8a72160e01b81526004810185905292519395506001600160a01b0391821694610100909104909116926321f8a721926024808201939291829003018186803b1580156112c457600080fd5b505afa1580156112d8573d6000803e3d6000fd5b505050506040513d60208110156112ee57600080fd5b50516001600160a01b031614158061131b57506000818152600960205260409020546001600160a01b0316155b1561132c5760009350505050610fb7565b5060010161123e565b50600191505090565b6113466131b7565b61134e612c81565b611356612c68565b6003546040805163159fa0d560e11b81526001600160a01b038581166004830152928316602482015290519290911691632b3f41aa9160448082019260009290919082900301818387803b1580156111f257600080fd5b6113b56131f7565b6002805460408051602081018790528082018690526060808201869052825180830390910181526080909101918290526001600160a01b039092169263907dff979291806031613e04823960310190506040518091039020886000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015611481578181015183820152602001611469565b50505050905090810190601f1680156114ae5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b1580156114d257600080fd5b505af11580156114e6573d6000803e3d6000fd5b5050505050505050565b601281565b600085846115038282613264565b61150b612c81565b611513612e20565b600354604080516327c319e960e11b81526001600160a01b039283166004820181905260248201819052604482018d9052606482018c9052608482018b905260a4820152600060c4820181905289841660e4830152610104820189905282519490931693634f8633d29361012480840194938390030190829087803b15801561159b57600080fd5b505af11580156115af573d6000803e3d6000fd5b505050506040513d60408110156115c557600080fd5b505198975050505050505050565b60085460ff1681565b6115e46131b7565b6115ec612c81565b6115f4612c68565b6003546040805163fd864ccf60e01b81526001600160a01b03858116600483015292831660248201529051929091169163fd864ccf9160448082019260009290919082900301818387803b1580156111f257600080fd5b6000611655612c68565b6001600160a01b03166332608039836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610d9857600080fd5b60006116a2612c68565b6001600160a01b0316637b1001b78360016040518363ffffffff1660e01b815260040180838152602001821515151581526020019250505060206040518083038186803b158015610d9857600080fd5b60006116fc612c68565b6001600160a01b0316634e99bda96040518163ffffffff1660e01b815260040160206040518083038186803b15801561173457600080fd5b505afa158015611748573d6000803e3d6000fd5b505050506040513d602081101561175e57600080fd5b5051905090565b6001546001600160a01b031681565b600061177e612d8a565b95945050505050565b61178f6132cb565b6117998282613338565b5050565b60006117a7612c68565b60048054604080516370a0823160e01b81526001600160a01b0387811694820194909452905193831693636bed041593879316916370a08231916024808301926020929190829003018186803b15801561180057600080fd5b505afa158015611814573d6000803e3d6000fd5b505050506040513d602081101561182a57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091528051604480840193829003018186803b15801561187557600080fd5b505afa158015611889573d6000803e3d6000fd5b505050506040513d6040811015610dc257600080fd5b6118a76131f7565b60028054604080516020810189905280820188905260608101879052608081018690526001600160a01b0385811660a0808401919091528351808403909101815260c0909201928390529092169263907dff97929180603e613e358239603e019050604051809103902061191a8b613455565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b8381101561198d578181015183820152602001611975565b50505050905090810190601f1680156119ba5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b1580156119de57600080fd5b505af11580156119f2573d6000803e3d6000fd5b50505050505050505050565b611a066131f7565b6002805460408051602081018690528082018590528151808203830181526060909101918290526001600160a01b039092169263907dff979291806027613ee9823960270190506040518091039020611a5e88613455565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015611ad1578181015183820152602001611ab9565b50505050905090810190601f168015611afe5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b158015611b2257600080fd5b505af1158015611b36573d6000803e3d6000fd5b50505050505050565b60048054604080516370a0823160e01b81526001600160a01b03858116948201949094529051600093909216916370a0823191602480820192602092909190829003018186803b158015610d9857600080fd5b6060611b9c612c68565b6001600160a01b03166372cb051f6040518163ffffffff1660e01b815260040160006040518083038186803b158015611bd457600080fd5b505afa158015611be8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015611c1157600080fd5b8101908080516040519392919084640100000000821115611c3157600080fd5b908301906020820185811115611c4657600080fd5b8251866020820283011164010000000082111715611c6357600080fd5b82525081516020918201928201910280838360005b83811015611c90578181015183820152602001611c78565b50505050905001604052505050905090565b6060611cac611fde565b905060005b8151811015611799576000828281518110611cc857fe5b602002602001015190506000600860019054906101000a90046001600160a01b03166001600160a01b031663dacb2d01838460405160200180807f5265736f6c766572206d697373696e67207461726765743a20000000000000008152506019018281526020019150506040516020818303038152906040526040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611d93578181015183820152602001611d7b565b50505050905090810190601f168015611dc05780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b158015611dde57600080fd5b505afa158015611df2573d6000803e3d6000fd5b505050506040513d6020811015611e0857600080fd5b505160008381526009602090815260409182902080546001600160a01b0319166001600160a01b03851690811790915582518681529182015281519293507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68929081900390910190a15050600101611cb1565b6001546001600160a01b03163314611ec45760405162461bcd60e51b8152600401808060200182810382526035815260200180613da76035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000611f41612c68565b6001600160a01b031663835e119c836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610d9857600080fd5b6000611f8e612c68565b6001600160a01b0316637b1001b78360006040518363ffffffff1660e01b815260040180838152602001821515151581526020019250505060206040518083038186803b158015610d9857600080fd5b606080611fe9613461565b60408051600180825281830190925291925060609190602080830190803883390190505090507453796e746865746978427269646765546f4261736560581b8160008151811061203557fe5b60200260200101818152505061204b8282613554565b9250505090565b61205a6131b7565b612062612c81565b61206a612c68565b600354604080516285c0d160e31b81526001600160a01b039283166004820152602481018590529051929091169163042e06889160448082019260009290919082900301818387803b1580156111f257600080fd5b6000546001600160a01b031681565b600085846120dc8282613264565b6120e4612c81565b6120ec612e20565b600354604080516327c319e960e11b81526001600160a01b038d8116600483018190529381166024830152604482018d9052606482018c9052608482018b905260a4820193909352600060c4820181905289841660e4830152610104820189905282519490931693634f8633d29361012480840194938390030190829087803b15801561217857600080fd5b505af115801561218c573d6000803e3d6000fd5b505050506040513d60408110156121a257600080fd5b50519998505050505050505050565b631cd554d160e21b81565b6006805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610e505780601f10610e2557610100808354040283529160200191610e50565b61221f612dd7565b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9181900360200190a150565b61227b6131b7565b612283612c81565b61228b612c68565b600354604080516324beb82560e11b81526001600160a01b0392831660048201529051929091169163497d704a9160248082019260009290919082900301818387803b1580156122da57600080fd5b505af11580156122ee573d6000803e3d6000fd5b505050505b565b6000806000612302612c81565b61230a612e20565b600354604080516306c5a00b60e21b81526001600160a01b0392831660048201526024810188905290519290911691631b16802c916044808201926060929091908290030181600087803b15801561236157600080fd5b505af1158015610f7d573d6000803e3d6000fd5b61237d613610565b600480546001600160a01b0319166001600160a01b03831617905561120b816136a9565b60006123ab612c68565b6001600160a01b031663a311c7c2836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b600061240a612c68565b6001600160a01b031663a5fdc5de836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b6000612469612c81565b612471612e37565b600354612487906001600160a01b031683612e8b565b50600354610ee9906001600160a01b031684846137d4565b6124a76131f7565b6002805460408051602081018690528082018590528151808203830181526060909101918290526001600160a01b039092169263907dff979291806028613ddc823960280190506040518091039020611a5e88613455565b6125076131b7565b61250f612c81565b612517612c68565b6003546040805163644bb89960e11b81526001600160a01b0392831660048201529051929091169163c89771329160248082019260009290919082900301818387803b1580156122da57600080fd5b61256e6137e1565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6125986131b7565b6125a0612c81565b6125a8612c68565b60035460408051632694552d60e21b81526001600160a01b03868116600483015292831660248201526044810185905290519290911691639a5154b49160648082019260009290919082900301818387803b15801561260657600080fd5b505af115801561261a573d6000803e3d6000fd5b505050505050565b600061117c612d8a565b6000838261263a8282613264565b612642612c81565b61264a612e20565b600354604080516327c319e960e11b81526001600160a01b038b8116600483018190529381166024830152604482018b9052606482018a90526084820189905260a48201849052600060c4830181905260e483019490945261010482018490528251941693634f8633d29361012480840194938390030190829087803b1580156126d357600080fd5b505af11580156126e7573d6000803e3d6000fd5b505050506040513d60408110156126fd57600080fd5b5051979650505050505050565b6000612714612c68565b6001600160a01b031663d37c4d8b84846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b15801561277157600080fd5b505afa158015612785573d6000803e3d6000fd5b505050506040513d602081101561279b57600080fd5b50519392505050565b6003546001600160a01b031681565b6127bb6132cb565b60006127c5613840565b90506127d18183613338565b806001600160a01b03166359974e38836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561281757600080fd5b505af115801561282b573d6000803e3d6000fd5b505050506040513d60208110156122ee57600080fd5b600061284b612c68565b6001600160a01b031663dbf633406040518163ffffffff1660e01b815260040160206040518083038186803b15801561173457600080fd5b6004805460408051636eb1769f60e11b81526001600160a01b0386811694820194909452848416602482015290516000939092169163dd62ed3e91604480820192602092909190829003018186803b15801561277157600080fd5b60006128e8612e37565b6128f0612c81565b6000806128fb612c68565b6003546040805163298f137d60e21b81526001600160a01b0389811660048301526024820189905292831660448201528151939092169263a63c4df49260648082019392918290030181600087803b15801561295657600080fd5b505af115801561296a573d6000803e3d6000fd5b505050506040513d604081101561298057600080fd5b50805160209091015160035491935091506129a9908690849084906001600160a01b0316613861565b60035461177e9086906001600160a01b0316846137d4565b6129c96131b7565b6129d1612c81565b6129d9612c68565b6003546040805163227635b160e11b81526001600160a01b038681166004830152928316602482015260448101859052905192909116916344ec6b629160648082019260009290919082900301818387803b15801561260657600080fd5b6004546001600160a01b031681565b6002546001600160a01b031681565b612a5d6132cb565b612a65612e37565b60048054604080516370a0823160e01b81526001600160a01b03868116948201949094529051929091169163b46310f6918591612afd91869186916370a08231916024808301926020929190829003018186803b158015612ac557600080fd5b505afa158015612ad9573d6000803e3d6000fd5b505050506040513d6020811015612aef57600080fd5b50519063ffffffff61393816565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612b4c57600080fd5b505af1158015612b60573d6000803e3d6000fd5b50505050612b7082600083613995565b600754612b83908263ffffffff61393816565b6007555050565b60008382612b988282613264565b612ba0612c81565b612ba8612e20565b600354604080516327c319e960e11b81526001600160a01b039283166004820181905260248201819052604482018b9052606482018a90526084820189905260a48201819052600060c4830181905260e4830191909152610104820181905282519490931693634f8633d29361012480840194938390030190829087803b158015612c3257600080fd5b505af1158015612c46573d6000803e3d6000fd5b505050506040513d6040811015612c5c57600080fd5b50519695505050505050565b6000612c7c6524b9b9bab2b960d11b6139e8565b905090565b6002546001600160a01b03163314801590612ca757506003546001600160a01b03163314155b156122f357600380546001600160a01b03191633179055565b60025460408051602080820185905282518083039091018152908201918290526001600160a01b039092169163907dff9791600390806021613ec8823960210190506040518091039020612d1388613455565b612d1c88613455565b60006040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018481526020018360001b81526020018281038252888181518152602001915080519060200190808383600083811015611ad1578181015183820152602001611ab9565b6040805162461bcd60e51b815260206004820152601b60248201527f43616e6e6f742062652072756e206f6e2074686973206c617965720000000000604482015290519081900360640190fd5b6000546001600160a01b031633146122f35760405162461bcd60e51b815260040180806020018281038252602f815260200180613e99602f913960400191505060405180910390fd5b6000612c7c6822bc31b430b733b2b960b91b6139e8565b612e3f613ac5565b6001600160a01b031663086dabd16040518163ffffffff1660e01b815260040160006040518083038186803b158015612e7757600080fd5b505afa1580156122ee573d6000803e3d6000fd5b600080612e96613adf565b60408051631167f01160e31b81526001600160a01b0387811660048301528251931692638b3f808892602480840193919291829003018186803b158015612edc57600080fd5b505afa158015612ef0573d6000803e3d6000fd5b505050506040513d6040811015612f0657600080fd5b505190508015610ee957600080612f1b612c68565b60048054604080516370a0823160e01b81526001600160a01b038b811694820194909452905193831693636bed0415938b9316916370a08231916024808301926020929190829003018186803b158015612f7457600080fd5b505afa158015612f88573d6000803e3d6000fd5b505050506040513d6020811015612f9e57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091528051604480840193829003018186803b158015612fe957600080fd5b505afa158015612ffd573d6000803e3d6000fd5b505050506040513d604081101561301357600080fd5b5080516020909101519092509050818511156130605760405162461bcd60e51b8152600401808060200182810382526026815260200180613e736026913960400191505060405180910390fd5b80156130b3576040805162461bcd60e51b815260206004820152601e60248201527f412073796e7468206f7220534e58207261746520697320696e76616c69640000604482015290519081900360640190fd5b50600195945050505050565b6004805460408051636eb1769f60e11b81526001600160a01b0387811694820194909452878416602482015290516000939092169163da46098c918791899161312c918891879163dd62ed3e91604480820192602092909190829003018186803b158015612ac557600080fd5b6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050600060405180830381600087803b15801561319457600080fd5b505af11580156131a8573d6000803e3d6000fd5b5050505061177e848484613afb565b6131bf613ac5565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015612e7757600080fd5b6131ff612e20565b6001600160a01b0316336001600160a01b0316146122f3576040805162461bcd60e51b815260206004820152601e60248201527f4f6e6c792045786368616e6765722063616e20696e766f6b6520746869730000604482015290519081900360640190fd5b61326c613ac5565b6001600160a01b0316631ce00ba283836040518363ffffffff1660e01b8152600401808381526020018281526020019250505060006040518083038186803b1580156132b757600080fd5b505afa15801561261a573d6000803e3d6000fd5b6132d3613d22565b6001600160a01b0316336001600160a01b0316146122f3576040805162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c7920626520696e766f6b656420627920627269646765000000604482015290519081900360640190fd5b60048054604080516370a0823160e01b81526001600160a01b03868116948201949094529051929091169163b46310f69185916133d091869186916370a08231916024808301926020929190829003018186803b15801561339857600080fd5b505afa1580156133ac573d6000803e3d6000fd5b505050506040513d60208110156133c257600080fd5b50519063ffffffff613d4516565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561341f57600080fd5b505af1158015613433573d6000803e3d6000fd5b50505050613442308383613995565b600754612b83908263ffffffff613d4516565b6001600160a01b031690565b60408051600580825260c082019092526060916020820160a0803883390190505090506d53796e746865746978537461746560901b816000815181106134a357fe5b6020026020010181815250506b53797374656d53746174757360a01b816001815181106134cc57fe5b6020026020010181815250506822bc31b430b733b2b960b91b816002815181106134f257fe5b6020026020010181815250506524b9b9bab2b960d11b8160038151811061351557fe5b602002602001018181525050722932bbb0b93239a234b9ba3934b13aba34b7b760691b8160048151811061354557fe5b60200260200101818152505090565b60608151835101604051908082528060200260200182016040528015613584578160200160208202803883390190505b50905060005b83518110156135c65783818151811061359f57fe5b60200260200101518282815181106135b357fe5b602090810291909101015260010161358a565b5060005b8251811015613609578281815181106135df57fe5b60200260200101518282865101815181106135f657fe5b60209081029190910101526001016135ca565b5092915050565b6002546001600160a01b0316331480159061363657506003546001600160a01b03163314155b1561364e57600380546001600160a01b031916331790555b6000546003546001600160a01b039081169116146122f3576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b600254604080516001600160a01b038481166020808401919091528351808403820181528385018086527f546f6b656e5374617465557064617465642861646472657373290000000000009052935192839003605a01832063907dff9760e01b8452600160248501819052604485018290526000606486018190526084860181905260a4860181905260c060048701908152875160c48801528751959098169763907dff97979692959394919384938493839260e490920191908a0190808383885b8381101561378357818101518382015260200161376b565b50505050905090810190601f1680156137b05780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b1580156111f257600080fd5b600061117c848484613afb565b6002546001600160a01b031633146122f3576040805162461bcd60e51b815260206004820152601760248201527f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000604482015290519081900360640190fd5b6000612c7c722932bbb0b93239a234b9ba3934b13aba34b7b760691b6139e8565b6002805460408051602081018790528082018690526001600160a01b03858116606080840191909152835180840390910181526080909201928390529092169263907dff979291806032613f108239603201905060405180910390206138c689613455565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b81526020018281038252888181518152602001915080519060200190808383600083811015611481578181015183820152602001611469565b60008282111561398f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60025460408051602080820185905282518083039091018152908201918290526001600160a01b039092169163907dff9791600390806021613f42823960210190506040518091039020612d1388613455565b600081815260096020908152604080832054815170026b4b9b9b4b7339030b2323932b9b99d1607d1b9381019390935260318084018690528251808503909101815260519093019091526001600160a01b031690816136095760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613a8a578181015183820152602001613a72565b50505050905090810190601f168015613ab75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6000612c7c6b53797374656d53746174757360a01b6139e8565b6000612c7c6d53796e746865746978537461746560901b6139e8565b60006001600160a01b03831615801590613b1e57506001600160a01b0383163014155b8015613b3857506002546001600160a01b03848116911614155b613b89576040805162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220746f2074686973206164647265737300604482015290519081900360640190fd5b60048054604080516370a0823160e01b81526001600160a01b03888116948201949094529051929091169163b46310f6918791613be991879186916370a08231916024808301926020929190829003018186803b158015612ac557600080fd5b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613c3857600080fd5b505af1158015613c4c573d6000803e3d6000fd5b505060048054604080516370a0823160e01b81526001600160a01b0389811694820194909452905192909116935063b46310f692508691613cb091879186916370a08231916024808301926020929190829003018186803b15801561339857600080fd5b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613cff57600080fd5b505af1158015613d13573d6000803e3d6000fd5b50505050610ee9848484613995565b6000612c7c7453796e746865746978427269646765546f4261736560581b6139e8565b600082820183811015613d9f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b939250505056fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e65727368697045786368616e67655265636c61696d28616464726573732c627974657333322c75696e743235362945786368616e6765547261636b696e6728627974657333322c627974657333322c75696e743235362c75696e743235362953796e746845786368616e676528616464726573732c627974657333322c75696e743235362c627974657333322c75696e743235362c616464726573732943616e6e6f74207472616e73666572207374616b6564206f7220657363726f77656420534e584f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e417070726f76616c28616464726573732c616464726573732c75696e743235362945786368616e676552656261746528616464726573732c627974657333322c75696e74323536294163636f756e744c69717569646174656428616464726573732c75696e743235362c75696e743235362c61646472657373295472616e7366657228616464726573732c616464726573732c75696e7432353629a265627a7a7231582046b95ecf0aafa1112c0aa66ee1e9d26dc5fd4e44c0171b7a85c17e188b20e23964736f6c63430005100032", "abi": [ { "inputs": [ @@ -14860,6 +14869,37 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "snxRedeemed", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountLiquidated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "liquidator", + "type": "address" + } + ], + "name": "AccountLiquidated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -15617,6 +15657,42 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "exchangeAtomically", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { "constant": false, "inputs": [ @@ -15773,7 +15849,7 @@ "outputs": [ { "internalType": "uint256", - "name": "amountReceived", + "name": "", "type": "uint256" } ], @@ -15822,21 +15898,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "integrationProxy", - "outputs": [ - { - "internalType": "contract Proxy", - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": true, "inputs": [], @@ -15937,12 +15998,12 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "account", "type": "address" }, { "internalType": "uint256", - "name": "", + "name": "susdAmount", "type": "uint256" } ], @@ -16204,21 +16265,6 @@ "stateMutability": "view", "type": "function" }, - { - "constant": false, - "inputs": [ - { - "internalType": "address payable", - "name": "_integrationProxy", - "type": "address" - } - ], - "name": "setIntegrationProxy", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, { "constant": false, "inputs": [ @@ -16504,15 +16550,15 @@ } ], "source": { - "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749", + "keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a", "urls": [ - "bzz-raw://45f229865baabb02bd1d2fc70e2689e8eddb335483c56fbc8a40aa839725831c", - "dweb:/ipfs/QmZ7hK15fu8JkDQRbHzVCHgyKLL6P7VJeuGEaUEY7ZHpom" + "bzz-raw://8eeb6e102aeb9e33d5bc3feafa27ced0cbf46166b8642b55711ae8088cbef77d", + "dweb:/ipfs/QmWnq7ZBagWFnHz4o82gyM193MZqeD5bqNiZxtd8R23N5D" ] }, "metadata": { "compiler": { - "version": "0.5.16-develop.2020.12.10+ovm+commit.25adf37d" + "version": "0.5.16+commit.9c3226ce" }, "language": "Solidity", "settings": { @@ -16529,10 +16575,10 @@ }, "sources": { "MintableSynthetix.sol": { - "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749", + "keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a", "urls": [ - "bzz-raw://45f229865baabb02bd1d2fc70e2689e8eddb335483c56fbc8a40aa839725831c", - "dweb:/ipfs/QmZ7hK15fu8JkDQRbHzVCHgyKLL6P7VJeuGEaUEY7ZHpom" + "bzz-raw://8eeb6e102aeb9e33d5bc3feafa27ced0cbf46166b8642b55711ae8088cbef77d", + "dweb:/ipfs/QmWnq7ZBagWFnHz4o82gyM193MZqeD5bqNiZxtd8R23N5D" ] } }, @@ -30460,6 +30506,1207 @@ }, "version": 1 } + }, + "CollateralEth": { + "bytecode": "6080604052600d805460ff191660011790553480156200001e57600080fd5b506040516200476938038062004769833981016040819052620000419162000150565b8585858585858380876001600160a01b0381166200007c5760405162461bcd60e51b8152600401620000739062000261565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91620000c99184906200023b565b60405180910390a150600280546001600160a01b039283166001600160a01b0319918216179091556006805498909216971696909617909555600492909255600a55600b5550506001600e5550620002e295505050505050565b80516200013081620002b2565b92915050565b80516200013081620002cc565b80516200013081620002d7565b60008060008060008060c087890312156200016a57600080fd5b600062000178898962000123565b96505060206200018b89828a0162000143565b95505060406200019e89828a0162000123565b9450506060620001b189828a0162000136565b9350506080620001c489828a0162000136565b92505060a0620001d789828a0162000136565b9150509295509295509295565b620001ef81620002a5565b82525050565b620001ef816200027c565b60006200020f60198362000273565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b604081016200024b8285620001e4565b6200025a6020830184620001f5565b9392505050565b60208082528101620001308162000200565b90815260200190565b6000620001308262000299565b90565b600062000130826200027c565b6001600160a01b031690565b600062000130826200028c565b620002bd816200027c565b8114620002c957600080fd5b50565b620002bd8162000289565b620002bd816200028c565b61447780620002f26000396000f3fe60806040526004361061020f5760003560e01c806372e18b6a11610118578063925ead11116100a0578063ba2de9bc1161006f578063ba2de9bc146105b0578063d2b8035a146105c5578063de81eda9146105e5578063e1ec3c6814610605578063f3f437031461063a5761020f565b8063925ead1114610546578063a76cdfa51461055b578063aa2d8ce31461057b578063b562a1ab1461059b5761020f565b8063846321a4116100e7578063846321a4146104af578063899ffef4146104cf5780638cd2e0c7146104f15780638da5cb5b1461051157806390abb4d9146105265761020f565b806372e18b6a14610445578063741853601461046557806379ba50971461047a5780637e1323551461048f5761020f565b8063379607f51161019b578063441a3e701161016a578063441a3e70146103bb57806347e7ef24146103db578063481c6a75146103ee57806353a47bb7146104035780635eb2ad01146104255761020f565b8063379607f51461034657806338245377146103665780634065b81b1461038657806341c738011461039b5761020f565b80631627540c116101e25780631627540c146102af57806323d60e2e146102cf5780632af64bd3146102ef57806330edd96114610311578063361e2086146103315761020f565b806304f3bcec1461021457806306c19e3f1461023f5780630710285c1461025f5780630aebeb4e14610281575b600080fd5b34801561022057600080fd5b5061022961065a565b6040516102369190614009565b60405180910390f35b61025261024d3660046136c0565b610669565b6040516102369190613f97565b34801561026b57600080fd5b5061027f61027a36600461355b565b61067f565b005b34801561028d57600080fd5b506102a161029c366004613684565b6106c5565b604051610236929190613fb3565b3480156102bb57600080fd5b5061027f6102ca3660046134e5565b61070e565b3480156102db57600080fd5b5061027f6102ea3660046135a8565b61076c565b3480156102fb57600080fd5b5061030461083b565b6040516102369190613f89565b34801561031d57600080fd5b5061025261032c366004613684565b610953565b34801561033d57600080fd5b50610252610971565b34801561035257600080fd5b5061027f610361366004613684565b610977565b34801561037257600080fd5b50610252610381366004613684565b610a4c565b34801561039257600080fd5b50610304610a5e565b3480156103a757600080fd5b506102526103b6366004613684565b610a67565b3480156103c757600080fd5b506102a16103d63660046136c0565b610b7f565b6102a16103e9366004613521565b610bca565b3480156103fa57600080fd5b50610229610be3565b34801561040f57600080fd5b50610418610bf2565b6040516102369190613f26565b34801561043157600080fd5b5061027f610440366004613521565b610c01565b34801561045157600080fd5b506103046104603660046135a8565b610c37565b34801561047157600080fd5b5061027f610cfb565b34801561048657600080fd5b5061027f610e4d565b34801561049b57600080fd5b506102526104aa3660046136c0565b610ee9565b3480156104bb57600080fd5b5061027f6104ca366004613684565b610f2e565b3480156104db57600080fd5b506104e4610f6b565b6040516102369190613f78565b3480156104fd57600080fd5b506102a161050c36600461355b565b6110fb565b34801561051d57600080fd5b50610418611116565b34801561053257600080fd5b5061027f610541366004613618565b611125565b34801561055257600080fd5b50610252611171565b34801561056757600080fd5b5061027f610576366004613684565b611177565b34801561058757600080fd5b50610252610596366004613684565b6111b4565b3480156105a757600080fd5b50610252611278565b3480156105bc57600080fd5b5061025261127e565b3480156105d157600080fd5b506102a16105e03660046136c0565b611284565b3480156105f157600080fd5b50610418610600366004613684565b611291565b34801561061157600080fd5b50610625610620366004613684565b6112ac565b604051610236999897969594939291906141ee565b34801561064657600080fd5b506102526106553660046134e5565b611306565b6002546001600160a01b031681565b60006106783484846000611318565b9392505050565b600061068c8484846119c0565b336000908152600f60205260409020549091506106af908263ffffffff611d2716565b336000908152600f602052604090205550505050565b6000806106d23384611d4c565b336000908152600f602052604090205491935091506106f7908263ffffffff611d2716565b336000908152600f60205260409020559092909150565b610716611e42565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290610761908390613f26565b60405180910390a150565b610774611e42565b82811461079c5760405162461bcd60e51b815260040161079390614048565b60405180910390fd5b60005b8381101561082c5760008585838181106107b557fe5b600780546001810182556000918252602090920293909301357fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909101819055925082916008915086868681811061080957fe5b60209081029290920135835250810191909152604001600020555060010161079f565b50610835610cfb565b50505050565b60006060610847610f6b565b905060005b815181101561094957600082828151811061086357fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a721906108b4908590600401613f97565b60206040518083038186803b1580156108cc57600080fd5b505afa1580156108e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109049190810190613503565b6001600160a01b031614158061092f57506000818152600360205260409020546001600160a01b0316155b156109405760009350505050610950565b5060010161084c565b5060019150505b90565b6007818154811061096057fe5b600091825260209091200154905081565b600c5481565b600e805460010190819055336000908152600f60205260409020546109a2908363ffffffff611e6e16565b336000818152600f602052604080822093909355915184906109c390613f1b565b60006040518083038185875af1925050503d8060008114610a00576040519150601f19603f3d011682016040523d82523d6000602084013e610a05565b606091505b5050905080610a265760405162461bcd60e51b815260040161079390614058565b50600e548114610a485760405162461bcd60e51b815260040161079390614168565b5050565b60086020526000908152604090205481565b600d5460ff1681565b6000610a71613407565b506000828152600560208181526040928390208351610120810185528154815260018201546001600160a01b03169281019290925260028101549382019390935260038301546060820152600483015460808201529082015460ff16151560a0820152600682015460c0820152600782015460e0820152600890910154610100820152610afc611e96565b6001600160a01b031663fbfeca4082600a546004546040518463ffffffff1660e01b8152600401610b2f939291906141a5565b60206040518083038186803b158015610b4757600080fd5b505afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061067891908101906136a2565b600080610b8c8484611eb7565b336000908152600f60205260409020549193509150610bb1908463ffffffff611d2716565b336000908152600f602052604090205590939092509050565b600080610bd8848434611f5c565b909590945092505050565b6006546001600160a01b031681565b6001546001600160a01b031681565b610c09611e42565b600090815260096020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b6007546000908414610c4b57506000610cf3565b60005b84811015610ced576000868683818110610c6457fe5b9050602002013590508060078381548110610c7b57fe5b906000526020600020015414610c9657600092505050610cf3565b60078281548110610ca357fe5b906000526020600020015460086000878786818110610cbe57fe5b9050602002013581526020019081526020016000205414610ce457600092505050610cf3565b50600101610c4e565b50600190505b949350505050565b6060610d05610f6b565b905060005b8151811015610a48576000828281518110610d2157fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610d639190613f10565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d8f929190613fc1565b60206040518083038186803b158015610da757600080fd5b505afa158015610dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ddf9190810190613503565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa6890610e3b9084908490613fa5565b60405180910390a15050600101610d0a565b6001546001600160a01b03163314610e775760405162461bcd60e51b815260040161079390614038565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c92610eba926001600160a01b0391821692911690613f4f565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000610ef3611e96565b6001600160a01b0316638a7399758484600a546004546040518563ffffffff1660e01b8152600401610b2f94939291906142da565b92915050565b610f36611e42565b600b8190556040517fd19fe8ad9152af12b174a60210fb798db0767d63973ebb97298dc44d67a5c82d90610761908390613f97565b606080610f7661202d565b60408051600680825260e08201909252919250606091906020820160c08038833901905050905066119959541bdbdb60ca1b81600081518110610fb557fe5b6020026020010181815250506c45786368616e6765526174657360981b81600181518110610fdf57fe5b6020026020010181815250506822bc31b430b733b2b960b91b8160028151811061100557fe5b6020026020010181815250506b53797374656d53746174757360a01b8160038151811061102e57fe5b6020026020010181815250506814de5b9d1a1cd554d160ba1b8160048151811061105457fe5b6020026020010181815250506d10dbdb1b185d195c985b155d1a5b60921b8160058151811061107f57fe5b6020026020010181815250506060611097838361207e565b90506110f38160078054806020026020016040519081016040528092919081815260200182805480156110e957602002820191906000526020600020905b8154815260200190600101908083116110d5575b505050505061207e565b935050505090565b60008061110a8533868661213a565b90969095509350505050565b6000546001600160a01b031681565b61112d611e42565b600d805460ff191682151517908190556040517f261991749e1b2436706a31bde8bf184bb37fe21e303709b78d3b881afacadaa2916107619160ff90911690613f89565b600a5481565b61117f611e42565b600c8190556040517fe7bd72551c54d568cd97b00dc52d2787b5c5d4f0070d3582c1e8ba25141f799c90610761908390613f97565b60006111be613407565b506000828152600560208181526040928390208351610120810185528154815260018201546001600160a01b03169281019290925260028101549382019390935260038301546060820152600483015460808201529082015460ff16151560a0820152600682015460c0820152600782015460e0820152600890910154610100820152611249611e96565b6001600160a01b031663e99f9647826004546040518363ffffffff1660e01b8152600401610b2f929190614188565b60045481565b600b5481565b600080610bd884846122e9565b6009602052600090815260409020546001600160a01b031681565b600560208190526000918252604090912080546001820154600283015460038401546004850154958501546006860154600787015460089097015495976001600160a01b0390951696939592949360ff9092169290919089565b600f6020526000908152604090205481565b600061132261272b565b61132a6127cd565b600d5460ff1661134c5760405162461bcd60e51b815260040161079390614118565b6000838152600860205260409020546113775760405162461bcd60e51b815260040161079390614068565b61137f612821565b6001600160a01b0316632528f0fe846040518263ffffffff1660e01b81526004016113aa9190613f97565b60206040518083038186803b1580156113c257600080fd5b505afa1580156113d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113fa9190810190613636565b156114175760405162461bcd60e51b8152600401610793906140f8565b600b548510156114395760405162461bcd60e51b815260040161079390614148565b6006546040516302d35b2d60e61b815260009182916001600160a01b039091169063b4d6cb40906114709089908990600401613fb3565b604080518083038186803b15801561148757600080fd5b505afa15801561149b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114bf9190810190613654565b915091508180156114ce575080155b6114ea5760405162461bcd60e51b8152600401610793906140d8565b6114f48786610ee9565b8611156115135760405162461bcd60e51b815260040161079390614138565b600061152a600c548861283c90919063ffffffff16565b9050600061153e888363ffffffff611e6e16565b9050600660009054906101000a90046001600160a01b03166001600160a01b031663b3b467326040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561159057600080fd5b505af11580156115a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115c891908101906136a2565b60408051610120810182528281523360208083019182528284018e8152606084018d8152608085018f81528d151560a08701908152600060c0880181815260e08901828152426101008b019081528c84526005988990529a9092209851895596516001890180546001600160a01b0319166001600160a01b03909216919091179055935160028801559151600387015551600486015551918401805460ff191692151592909217909155905160068301555160078201559051600882015590955061169290612851565b61169c8288612943565b851561188f576116aa612b2f565b6001600160a01b031663867904b4336116c1612821565b6001600160a01b031663654a60ac8b86631cd554d160e21b6040518463ffffffff1660e01b81526004016116f793929190613fe1565b60206040518083038186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061174791908101906136a2565b6040518363ffffffff1660e01b8152600401611764929190613f34565b600060405180830381600087803b15801561177e57600080fd5b505af1158015611792573d6000803e3d6000fd5b505060065460405163e31f27c160e01b81526001600160a01b03909116925063e31f27c191506117c8908a908c90600401613fb3565b600060405180830381600087803b1580156117e257600080fd5b505af11580156117f6573d6000803e3d6000fd5b5050506000888152600960205260409020546001600160a01b031615905061188a576000878152600960205260409081902054905163db454a5160e01b81526001600160a01b039091169063db454a51906118579033908c90600401613f34565b600060405180830381600087803b15801561187157600080fd5b505af1158015611885573d6000803e3d6000fd5b505050505b61196b565b6000878152600860205260409020546118a790612b46565b6001600160a01b031663867904b433836040518363ffffffff1660e01b81526004016118d4929190613f34565b600060405180830381600087803b1580156118ee57600080fd5b505af1158015611902573d6000803e3d6000fd5b50506006546040516375ca5def60e11b81526001600160a01b03909116925063eb94bbde9150611938908a908c90600401613fb3565b600060405180830381600087803b15801561195257600080fd5b505af1158015611966573d6000803e3d6000fd5b505050505b336001600160a01b03167f604952b18be5fed608cbdd28101dc57bd667055c9678ec6d44fb1d8e4c7c172a868a8c8b876040516119ac9594939291906142f5565b60405180910390a250505050949350505050565b60006119ca61272b565b6119d26127cd565b600082116119f25760405162461bcd60e51b815260040161079390614178565b60006119fe8486612b51565b9050611a0f33826003015485612ba5565b600a54611a1a611e96565b6001600160a01b031663e99f9647836004546040518363ffffffff1660e01b8152600401611a499291906141d0565b60206040518083038186803b158015611a6157600080fd5b505afa158015611a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a9991908101906136a2565b10611ab65760405162461bcd60e51b815260040161079390614158565b6000611ac0611e96565b6001600160a01b031663fbfeca4083600a546004546040518463ffffffff1660e01b8152600401611af3939291906141df565b60206040518083038186803b158015611b0b57600080fd5b505afa158015611b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b4391908101906136a2565b90506000848210611b545784611b56565b815b90506000611b7584600601548560040154611d2790919063ffffffff16565b9050808210611b9657611b89883386612c5d565b9550610678945050505050565b611ba533856003015484612ba5565b611baf8483612cce565b611bb7611e96565b6001600160a01b0316633c4aa0f38560030154846004546040518463ffffffff1660e01b8152600401611bec93929190613fe1565b60206040518083038186803b158015611c0457600080fd5b505afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c3c91908101906136a2565b6002850154909550611c54908663ffffffff611e6e16565b60028501556003840154600090815260086020526040902054611c7690612b46565b6001600160a01b0316639dc29fac33846040518363ffffffff1660e01b8152600401611ca3929190613f34565b600060405180830381600087803b158015611cbd57600080fd5b505af1158015611cd1573d6000803e3d6000fd5b50505050876001600160a01b03167fb6e43890aeea54fbe6c0ed628e78172a0ff30bbcb1d70d8b130b12c366bac4c588338589604051611d149493929190614274565b60405180910390a2505050509392505050565b6000828201838110156106785760405162461bcd60e51b815260040161079390614078565b600080611d5761272b565b611d5f6127cd565b6000611d6b8486612b51565b60408051610120810182528254815260018301546001600160a01b031660208201526002830154918101919091526003820154606082015260048201546080820152600582015460ff16151560a0820152600682015460c0820152600782015460e08201526008820154610100820152909150611de790612ebd565b611df2858683612f0a565b60405191945092506001600160a01b038616907fcab22a4e95d29d40da2ace3f6ec72b49954a9bc7b2584f8fd47bf7f357a3ed6f90611e32908790613f97565b60405180910390a2509250929050565b6000546001600160a01b03163314611e6c5760405162461bcd60e51b8152600401610793906140b8565b565b600082821115611e905760405162461bcd60e51b815260040161079390614098565b50900390565b6000611eb26d10dbdb1b185d195c985b155d1a5b60921b613170565b905090565b600080611ec261272b565b611eca6127cd565b6000611ed68533612b51565b6002810154909150611eee908563ffffffff611e6e16565b6002820155611efc816131cd565b336001600160a01b03167ffae26280bca25d80f1501a9e363c73d3845e651c9aaae54f1fc09a9dcd5f330386868460020154604051611f3d93929190613fe1565b60405180910390a28060040154816002015492509250505b9250929050565b600080611f6761272b565b611f6f6127cd565b60008311611f8f5760405162461bcd60e51b815260040161079390614128565b60008481526005602052604090206007810154611fab90613206565b611fb481612851565b6002810154611fc9908563ffffffff611d2716565b600282018190556040516001600160a01b038816917f0b1992dffc262be88559dcaf96464e9d661d8bfca7e82f2bb73e31932a82187c9161200e918991899190613fe1565b60405180910390a2806004015481600201549250925050935093915050565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b8160008151811061206f57fe5b60200260200101818152505090565b606081518351016040519080825280602002602001820160405280156120ae578160200160208202803883390190505b50905060005b83518110156120f0578381815181106120c957fe5b60200260200101518282815181106120dd57fe5b60209081029190910101526001016120b4565b5060005b82518110156121335782818151811061210957fe5b602002602001015182828651018151811061212057fe5b60209081029190910101526001016120f4565b5092915050565b60008061214561272b565b61214d6127cd565b6000848152600560208181526040928390208351610120810185528154815260018201546001600160a01b03169281019290925260028101549382019390935260038301546060820152600483015460808201529082015460ff16151560a0820152600682015460c0820152600782015460e082015260088201546101008201526121d790612ebd565b6121e686826003015486612ba5565b6121ef81612851565b6121f98185612cce565b600381015460009081526008602052604090205461221690612b46565b6001600160a01b0316639dc29fac87866040518363ffffffff1660e01b8152600401612243929190613f6a565b600060405180830381600087803b15801561225d57600080fd5b505af1158015612271573d6000803e3d6000fd5b50505050428160080181905550856001600160a01b0316876001600160a01b03167fdf10512219e869922340b1b24b21d7d79bf71f411a6391cc7c3ef5dd2fe89e7f878785600401546040516122c993929190613fe1565b60405180910390a380600401548160020154925092505094509492505050565b6000806122f461272b565b6122fc6127cd565b60006123088533612b51565b60408051610120810182528254815260018301546001600160a01b031660208201526002830154918101919091526003820154606082015260048201546080820152600582015460ff16151560a0820152600682015460c0820152600782015460e0820152600882015461010082015290915061238490612ebd565b6004810154612399908563ffffffff611d2716565b60048201556123a7816131cd565b60006123be600c548661283c90919063ffffffff16565b905060006123d2868363ffffffff611e6e16565b600584015490915060ff16156125df57600654600384015460405163e31f27c160e01b81526001600160a01b039092169163e31f27c191612417918a90600401613fb3565b600060405180830381600087803b15801561243157600080fd5b505af1158015612445573d6000803e3d6000fd5b50505050612451612b2f565b6001600160a01b031663867904b433612468612821565b6001600160a01b031663654a60ac876003015486631cd554d160e21b6040518463ffffffff1660e01b81526004016124a293929190613fe1565b60206040518083038186803b1580156124ba57600080fd5b505afa1580156124ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124f291908101906136a2565b6040518363ffffffff1660e01b815260040161250f929190613f34565b600060405180830381600087803b15801561252957600080fd5b505af115801561253d573d6000803e3d6000fd5b5050505060038301546000908152600960205260409020546001600160a01b0316156125da5760038301546000908152600960205260409081902054905163db454a5160e01b81526001600160a01b039091169063db454a51906125a79033908a90600401613f34565b600060405180830381600087803b1580156125c157600080fd5b505af11580156125d5573d6000803e3d6000fd5b505050505b6126c3565b60065460038401546040516375ca5def60e11b81526001600160a01b039092169163eb94bbde91612614918a90600401613fb3565b600060405180830381600087803b15801561262e57600080fd5b505af1158015612642573d6000803e3d6000fd5b50505060038401546000908152600860205260409020546126639150612b46565b6001600160a01b031663867904b433836040518363ffffffff1660e01b8152600401612690929190613f34565b600060405180830381600087803b1580156126aa57600080fd5b505af11580156126be573d6000803e3d6000fd5b505050505b6126d1828460030154612943565b42600884015560405133907f5754fe57f36ac0f121901d7555aba517e6608590429d86a81c662cf3583106549061270b908a908a90613fb3565b60405180910390a282600401548360020154945094505050509250929050565b612733612821565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b81526004016127609190613f97565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127b09190810190613636565b15611e6c5760405162461bcd60e51b8152600401610793906140f8565b6127d5613223565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561280d57600080fd5b505afa158015610835573d6000803e3d6000fd5b6000611eb26c45786368616e6765526174657360981b613170565b60006106788383670de0b6b3a764000061323d565b600654600782015460038301546005840154604051634002a33360e11b815260009485946001600160a01b03909116936380054666936128999360ff909116906004016142b2565b6040805180830381600087803b1580156128b257600080fd5b505af11580156128c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128ea91908101906136df565b9150915060008360070154600014612916576004840154612911908463ffffffff61327916565b612919565b60005b6006850154909150612931908263ffffffff611d2716565b60068501555060079092019190915550565b8115610a4857631cd554d160e21b81146129e85761295f612821565b6001600160a01b031663654a60ac8284631cd554d160e21b6040518463ffffffff1660e01b815260040161299593929190613fe1565b60206040518083038186803b1580156129ad57600080fd5b505afa1580156129c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129e591908101906136a2565b91505b6129f0612b2f565b6001600160a01b031663867904b4612a066132a3565b6001600160a01b031663eb1edd616040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3e57600080fd5b505afa158015612a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a769190810190613503565b846040518363ffffffff1660e01b8152600401612a94929190613f6a565b600060405180830381600087803b158015612aae57600080fd5b505af1158015612ac2573d6000803e3d6000fd5b50505050612ace6132a3565b6001600160a01b03166322bf55ef836040518263ffffffff1660e01b8152600401612af99190613f97565b600060405180830381600087803b158015612b1357600080fd5b505af1158015612b27573d6000803e3d6000fd5b505050505050565b6000611eb26814de5b9d1a1cd554d160ba1b613170565b6000610f2882613170565b60008281526005602052604090206007810154612b6d90613206565b60018101546001600160a01b03838116911614612b9c5760405162461bcd60e51b815260040161079390614108565b610f2881612851565b6000828152600860205260409020548190612bbf90612b46565b6001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401612bea9190613f26565b60206040518083038186803b158015612c0257600080fd5b505afa158015612c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c3a91908101906136a2565b1015612c585760405162461bcd60e51b8152600401610793906140a8565b505050565b600080612c6b858585612f0a565b8092508193505050836001600160a01b0316856001600160a01b03167f697721ed1b9d4866cb1aaa0692f62bb3abc1b01c2dafeaad053ffd4532aa7dbb85600001548585604051612cbe93929190613fe1565b60405180910390a3935093915050565b60008111612cee5760405162461bcd60e51b815260040161079390614178565b600682015415612d5057600082600601548211612d0b5781612d11565b82600601545b6006840154909150612d29908263ffffffff611e6e16565b6006840155612d3e828263ffffffff611e6e16565b9150612d4e818460030154612943565b505b8015610a48576004820154612d6b908263ffffffff611e6e16565b6004830155600582015460ff1615612e88576006546003830154604051635246f2b960e01b81526001600160a01b0390921691635246f2b991612db2918590600401613fb3565b600060405180830381600087803b158015612dcc57600080fd5b505af1158015612de0573d6000803e3d6000fd5b5050505060038201546000908152600960205260409020546001600160a01b031615612e8357600382015460009081526009602052604090819020546001840154915163f3fef3a360e01b81526001600160a01b039182169263f3fef3a392612e50929116908590600401613f34565b600060405180830381600087803b158015612e6a57600080fd5b505af1158015612e7e573d6000803e3d6000fd5b505050505b610a48565b600654600383015460405163e50a31b360e01b81526001600160a01b039092169163e50a31b391612af9918590600401613fb3565b612eca8160e00151613206565b42612ee9612ed7306132b8565b6101008401519063ffffffff611d2716565b1115612f075760405162461bcd60e51b8152600401610793906140e8565b50565b6000806000612f2a84600601548560040154611d2790919063ffffffff16565b90508360040154925083600201549150612f4985856003015483612ba5565b6003840154600090815260086020526040902054612f6690612b46565b6001600160a01b0316639dc29fac86836040518363ffffffff1660e01b8152600401612f93929190613f6a565b600060405180830381600087803b158015612fad57600080fd5b505af1158015612fc1573d6000803e3d6000fd5b50505050600584015460ff16156130df576006546003850154600480870154604051635246f2b960e01b81526001600160a01b0390941693635246f2b99361300c9390929101613fb3565b600060405180830381600087803b15801561302657600080fd5b505af115801561303a573d6000803e3d6000fd5b5050505060038401546000908152600960205260409020546001600160a01b0316156130da5760038401546000908152600960205260409081902054600480870154925163f3fef3a360e01b81526001600160a01b039092169263f3fef3a3926130a7928b929101613f6a565b600060405180830381600087803b1580156130c157600080fd5b505af11580156130d5573d6000803e3d6000fd5b505050505b61314c565b600654600385015460048087015460405163e50a31b360e01b81526001600160a01b039094169363e50a31b3936131199390929101613fb3565b600060405180830381600087803b15801561313357600080fd5b505af1158015613147573d6000803e3d6000fd5b505050505b61315e84600601548560030154612943565b6131678461338b565b50935093915050565b60008181526003602090815260408083205490516001600160a01b0390911691821515916131a091869101613ef0565b604051602081830303815290604052906121335760405162461bcd60e51b81526004016107939190614017565b60048101546131db57612f07565b600a5481546131e9906111b4565b11612f075760405162461bcd60e51b815260040161079390614028565b80612f075760405162461bcd60e51b815260040161079390614088565b6000611eb26b53797374656d53746174757360a01b613170565b600080600a8304613254868663ffffffff6133b016565b8161325b57fe5b0490506005600a82061061326d57600a015b600a9004949350505050565b6000670de0b6b3a7640000613294848463ffffffff6133b016565b8161329b57fe5b049392505050565b6000611eb266119959541bdbdb60ca1b613170565b60006132c26133ea565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6f696e746572616374696f6e44656c617960801b85604051602001613308929190613eca565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b815260040161333b929190613fb3565b60206040518083038186803b15801561335357600080fd5b505afa158015613367573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f2891908101906136a2565b6000600482018190556002820181905560068201819055600782015542600890910155565b6000826133bf57506000610f28565b828202828482816133cc57fe5b04146106785760405162461bcd60e51b8152600401610793906140c8565b6000611eb26e466c657869626c6553746f7261676560881b613170565b6040518061012001604052806000815260200160006001600160a01b031681526020016000815260200160008019168152602001600081526020016000151581526020016000815260200160008152602001600081525090565b8035610f288161440e565b8051610f288161440e565b60008083601f84011261348957600080fd5b50813567ffffffffffffffff8111156134a157600080fd5b602083019150836020820283011115611f5557600080fd5b8035610f2881614422565b8051610f2881614422565b8035610f288161442b565b8051610f288161442b565b6000602082840312156134f757600080fd5b6000610cf38484613461565b60006020828403121561351557600080fd5b6000610cf3848461346c565b6000806040838503121561353457600080fd5b60006135408585613461565b9250506020613551858286016134cf565b9150509250929050565b60008060006060848603121561357057600080fd5b600061357c8686613461565b935050602061358d868287016134cf565b925050604061359e868287016134cf565b9150509250925092565b600080600080604085870312156135be57600080fd5b843567ffffffffffffffff8111156135d557600080fd5b6135e187828801613477565b9450945050602085013567ffffffffffffffff81111561360057600080fd5b61360c87828801613477565b95989497509550505050565b60006020828403121561362a57600080fd5b6000610cf384846134b9565b60006020828403121561364857600080fd5b6000610cf384846134c4565b6000806040838503121561366757600080fd5b600061367385856134c4565b9250506020613551858286016134c4565b60006020828403121561369657600080fd5b6000610cf384846134cf565b6000602082840312156136b457600080fd5b6000610cf384846134da565b600080604083850312156136d357600080fd5b600061354085856134cf565b600080604083850312156136f257600080fd5b60006136fe85856134da565b9250506020613551858286016134da565b600061371b83836137ae565b505060200190565b61372c8161437b565b82525050565b61372c8161436b565b61372c6137478261436b565b6143ed565b600061375782614347565b613761818561434b565b935061376c83614341565b8060005b8381101561379a578151613784888261370f565b975061378f83614341565b925050600101613770565b509495945050505050565b61372c81614376565b61372c81610950565b61372c6137c382610950565b610950565b61372c81614382565b60006137dc82614347565b6137e6818561434b565b93506137f681856020860161438d565b6137ff816143fe565b9093019392505050565b6000613816600e8361434b565b6d43726174696f20746f6f206c6f7760901b815260200192915050565b600061384060358361434b565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b600061389760158361434b565b74082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b815260200192915050565b60006138c8600f8361434b565b6e151c985b9cd9995c8819985a5b1959608a1b815260200192915050565b60006138f360148361434b565b734e6f7420616c6c6f77656420746f20697373756560601b815260200192915050565b6000613923601b8361434b565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b600061395c600e8361434b565b6d131bd85b881a5cc818db1bdcd95960921b815260200192915050565b6000613986601e8361434b565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b60006139bf601183614354565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b60006139ec60128361434b565b714e6f7420656e6f7567682062616c616e636560701b815260200192915050565b6000613a1a602f8361434b565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b6000613a6b60218361434b565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613aae601a8361434b565b7f44656274206c696d6974206f7220696e76616c69642072617465000000000000815260200192915050565b6000613ae760138361434b565b72149958d95b9d1b1e481a5b9d195c9858dd1959606a1b815260200192915050565b6000613b16601983614354565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000613b4f600c8361434b565b6b496e76616c6964207261746560a01b815260200192915050565b6000613b7760108361434b565b6f26bab9ba103132903137b93937bbb2b960811b815260200192915050565b6000610f28600083614354565b6000613bb0600d8361434b565b6c13dc195b88191a5cd8589b1959609a1b815260200192915050565b6000613bd960178361434b565b7f4465706f736974206d7573742062652061626f76652030000000000000000000815260200192915050565b6000613c1260178361434b565b7f457863656564206d617820626f72726f7720706f776572000000000000000000815260200192915050565b6000613c4b60158361434b565b74139bdd08195b9bdd59da0818dbdb1b185d195c985b605a1b815260200192915050565b6000613c7c60168361434b565b7543726174696f2061626f7665206c697120726174696f60501b815260200192915050565b6000613cae601f8361434b565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000613ce760178361434b565b7f5061796d656e74206d7573742062652061626f76652030000000000000000000815260200192915050565b8051610120830190613d2584826137ae565b506020820151613d386020850182613732565b506040820151613d4b60408501826137ae565b506060820151613d5e60608501826137ae565b506080820151613d7160808501826137ae565b5060a0820151613d8460a08501826137a5565b5060c0820151613d9760c08501826137ae565b5060e0820151613daa60e08501826137ae565b506101008201516108356101008501826137ae565b8054610120830190613dd0816143df565b613dda85826137ae565b50506001820154613dea816143b9565b613df76020860182613732565b50506002820154613e07816143df565b613e1460408601826137ae565b50506003820154613e24816143df565b613e3160608601826137ae565b50506004820154613e41816143df565b613e4e60808601826137ae565b50506005820154613e5e816143cc565b613e6b60a08601826137a5565b50506006820154613e7b816143df565b613e8860c08601826137ae565b50506007820154613e98816143df565b613ea560e08601826137ae565b50506008820154613eb5816143df565b613ec36101008601826137ae565b5050505050565b6000613ed682856137b7565b602082019150613ee6828461373b565b5060140192915050565b6000613efb826139b2565b9150613f0782846137b7565b50602001919050565b6000613efb82613b09565b6000610f2882613b96565b60208101610f288284613732565b60408101613f428285613723565b61067860208301846137ae565b60408101613f5d8285613732565b6106786020830184613732565b60408101613f428285613732565b60208082528101610678818461374c565b60208101610f2882846137a5565b60208101610f2882846137ae565b60408101613f5d82856137ae565b60408101613f4282856137ae565b60408101613fcf82856137ae565b8181036020830152610cf381846137d1565b60608101613fef82866137ae565b613ffc60208301856137ae565b610cf360408301846137ae565b60208101610f2882846137c8565b6020808252810161067881846137d1565b60208082528101610f2881613809565b60208082528101610f2881613833565b60208082528101610f288161388a565b60208082528101610f28816138bb565b60208082528101610f28816138e6565b60208082528101610f2881613916565b60208082528101610f288161394f565b60208082528101610f2881613979565b60208082528101610f28816139df565b60208082528101610f2881613a0d565b60208082528101610f2881613a5e565b60208082528101610f2881613aa1565b60208082528101610f2881613ada565b60208082528101610f2881613b42565b60208082528101610f2881613b6a565b60208082528101610f2881613ba3565b60208082528101610f2881613bcc565b60208082528101610f2881613c05565b60208082528101610f2881613c3e565b60208082528101610f2881613c6f565b60208082528101610f2881613ca1565b60208082528101610f2881613cda565b61014081016141978285613d13565b6106786101208301846137ae565b61016081016141b48286613d13565b6141c26101208301856137ae565b610cf36101408301846137ae565b61014081016141978285613dbf565b61016081016141b48286613dbf565b61012081016141fd828c6137ae565b61420a602083018b613732565b614217604083018a6137ae565b61422460608301896137ae565b61423160808301886137ae565b61423e60a08301876137a5565b61424b60c08301866137ae565b61425860e08301856137ae565b6142666101008301846137ae565b9a9950505050505050505050565b6080810161428282876137ae565b61428f6020830186613723565b61429c60408301856137ae565b6142a960608301846137ae565b95945050505050565b606081016142c082866137ae565b6142cd60208301856137ae565b610cf360408301846137a5565b608081016142e882876137ae565b61428f60208301866137ae565b60a0810161430382886137ae565b61431060208301876137ae565b61431d60408301866137ae565b61432a60608301856137ae565b61433760808301846137ae565b9695505050505050565b60200190565b5190565b90815260200190565b919050565b6001600160a01b031690565b60ff1690565b6000610f2882614359565b151590565b6000610f28825b6000610f288261436b565b60005b838110156143a8578181015183820152602001614390565b838111156108355750506000910152565b6000610f286143c783610950565b614359565b6000610f286143da83610950565b614365565b6000610f286137c383610950565b6000610f28826000610f2882614408565b601f01601f191690565b60601b90565b6144178161436b565b8114612f0757600080fd5b61441781614376565b6144178161095056fea365627a7a723158207ea733850eab679e1a0115a60d2318d891ec530c9063b5a96fa092a6360815b46c6578706572696d656e74616cf564736f6c63430005100040", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "contract ICollateralManager", + "name": "_manager", + "type": "address" + }, + { + "internalType": "address", + "name": "_resolver", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_collateralKey", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_minCratio", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minCollateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "name", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "destination", + "type": "address" + } + ], + "name": "CacheUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "canOpenLoans", + "type": "bool" + } + ], + "name": "CanOpenLoansUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountDeposited", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralAfter", + "type": "uint256" + } + ], + "name": "CollateralDeposited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountWithdrawn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralAfter", + "type": "uint256" + } + ], + "name": "CollateralWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "issueFeeRate", + "type": "uint256" + } + ], + "name": "IssueFeeRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "LoanClosed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountLiquidated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralLiquidated", + "type": "uint256" + } + ], + "name": "LoanClosedByLiquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountRepaid", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralAfter", + "type": "uint256" + } + ], + "name": "LoanClosedByRepayment", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "issuanceFee", + "type": "uint256" + } + ], + "name": "LoanCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "LoanDrawnDown", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountLiquidated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralLiquidated", + "type": "uint256" + } + ], + "name": "LoanPartiallyLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "repayer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountRepaid", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountAfter", + "type": "uint256" + } + ], + "name": "LoanRepaymentMade", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "minCollateral", + "type": "uint256" + } + ], + "name": "MinCollateralUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnerNominated", + "type": "event" + }, + { + "constant": false, + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "rewardsContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "synth", + "type": "bytes32" + } + ], + "name": "addRewardsContracts", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32[]", + "name": "_synthNamesInResolver", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_synthKeys", + "type": "bytes32[]" + } + ], + "name": "addSynths", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32[]", + "name": "_synthNamesInResolver", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_synthKeys", + "type": "bytes32[]" + } + ], + "name": "areSynthsAndCurrenciesSet", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "canOpenLoans", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "claim", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "close", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "collateralKey", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "collateralRatio", + "outputs": [ + { + "internalType": "uint256", + "name": "cratio", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "draw", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isResolverCached", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "issueFeeRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "liquidate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "liquidationAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "liqAmount", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "loans", + "outputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "short", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "accruedInterest", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "interestIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastInteraction", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "contract ICollateralManager", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + } + ], + "name": "maxLoan", + "outputs": [ + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minCollateral", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minCratio", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "nominateNewOwner", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nominatedOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + } + ], + "name": "open", + "outputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "pendingWithdrawals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "rebuildCache", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "repay", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "resolver", + "outputs": [ + { + "internalType": "contract AddressResolver", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "resolverAddressesRequired", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "addresses", + "type": "bytes32[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bool", + "name": "_canOpenLoans", + "type": "bool" + } + ], + "name": "setCanOpenLoans", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_issueFeeRate", + "type": "uint256" + } + ], + "name": "setIssueFeeRate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_minCollateral", + "type": "uint256" + } + ], + "name": "setMinCollateral", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "shortingRewards", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "synths", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "synthsByKey", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "source": { + "keccak256": "0xd83c3667bcacd4d33cf0fc649cee03d85e7d3914abb7ce6c9898e6ee1d66da81", + "urls": [ + "bzz-raw://77bd631dcee01051f611ea2927feb37c87f5532ce90537b2dc9b8952b85c3576", + "dweb:/ipfs/QmWHiciYDoG7sNnyA7kUzeSmQy4EVV8ktrDNVHDuQhq7tx" + ] + }, + "metadata": { + "compiler": { + "version": "0.5.16+commit.9c3226ce" + }, + "language": "Solidity", + "settings": { + "compilationTarget": { + "CollateralEth.sol": "CollateralEth" + }, + "evmVersion": "istanbul", + "libraries": {}, + "optimizer": { + "enabled": true, + "runs": 200 + }, + "remappings": [] + }, + "sources": { + "CollateralEth.sol": { + "keccak256": "0xd83c3667bcacd4d33cf0fc649cee03d85e7d3914abb7ce6c9898e6ee1d66da81", + "urls": [ + "bzz-raw://77bd631dcee01051f611ea2927feb37c87f5532ce90537b2dc9b8952b85c3576", + "dweb:/ipfs/QmWHiciYDoG7sNnyA7kUzeSmQy4EVV8ktrDNVHDuQhq7tx" + ] + } + }, + "version": 1 + } } } } diff --git a/publish/deployed/kovan-ovm/params.json b/publish/deployed/kovan-ovm/params.json index 140bbd85c8..f6b7f5807e 100644 --- a/publish/deployed/kovan-ovm/params.json +++ b/publish/deployed/kovan-ovm/params.json @@ -18,7 +18,7 @@ "SHORTS": ["sBTC", "sETH", "sLINK", "sUNI", "sAAVE"], "MAX_DEBT": "75000000000000000000000000", "MAX_SKEW_RATE": "200000000000000000", - "BASE_BORROW_RATE": "158443823", + "BASE_BORROW_RATE": "950662938", "BASE_SHORT_RATE": "158443823" } }, @@ -32,5 +32,14 @@ "INTERACTION_DELAY": "0", "COLLAPSE_FEE_RATE": "0" } + }, + { + "name": "COLLATERAL_ETH", + "value": { + "SYNTHS": ["sUSD"], + "MIN_CRATIO": "1200000000000000000", + "MIN_COLLATERAL": "100000000000000000", + "ISSUE_FEE_RATE": "0" + } } ] diff --git a/publish/deployed/kovan-ovm/versions.json b/publish/deployed/kovan-ovm/versions.json index 1398c7e67e..32a1899fae 100644 --- a/publish/deployed/kovan-ovm/versions.json +++ b/publish/deployed/kovan-ovm/versions.json @@ -778,8 +778,9 @@ }, "Synthetix": { "address": "0xCAA5c8e9E67BBa010D2D7F589F02d588Fb49f93D", - "status": "current", - "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749" + "status": "replaced", + "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749", + "replaced_in": "v2.56.0-alpha" }, "DebtCache": { "address": "0xCF4a31F3C7E245F8de884907aEFF1841C042cF41", @@ -967,5 +968,41 @@ "keccak256": "0x582cac91f50cfefc154d67097081d0dd0d4877333df51c3cfe19485f80ef7e74" } } + }, + "v2.56.0-alpha": { + "tag": "v2.56.0-alpha", + "fulltag": "v2.56.0-alpha", + "release": "Alhena", + "network": "kovan", + "date": "2021-12-07T16:13:13-05:00", + "commit": "79b5acd4a4557d9892409dad70f139f54cf5e6d5", + "contracts": { + "Synthetix": { + "address": "0x752b2e77769a8832E657CB9f7318543e03c13627", + "status": "replaced", + "keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a", + "replaced_in": "v2.56.1-alpha" + } + } + }, + "v2.56.1-alpha": { + "tag": "v2.56.1-alpha", + "fulltag": "v2.56.1-alpha", + "release": "Alhena", + "network": "kovan", + "date": "2021-12-15T05:19:57-05:00", + "commit": "64f28868700af3cbc1fae6522d7fd29d059d7577", + "contracts": { + "Synthetix": { + "address": "0x099B3881d63d3Eef0ec32783Aa64B726672213E2", + "status": "current", + "keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a" + }, + "CollateralEth": { + "address": "0xc7960401a5Ca5A201d41Cf6532C7d2803f8D5Ce4", + "status": "current", + "keccak256": "0xd83c3667bcacd4d33cf0fc649cee03d85e7d3914abb7ce6c9898e6ee1d66da81" + } + } } } diff --git a/publish/deployed/local-ovm/params.json b/publish/deployed/local-ovm/params.json index d670223afe..d0978a2684 100644 --- a/publish/deployed/local-ovm/params.json +++ b/publish/deployed/local-ovm/params.json @@ -18,7 +18,7 @@ "SHORTS": ["sBTC", "sETH"], "MAX_DEBT": "75000000000000000000000000", "MAX_SKEW_RATE": "200000000000000000", - "BASE_BORROW_RATE": "158443823", + "BASE_BORROW_RATE": "950662938", "BASE_SHORT_RATE": "158443823" } }, @@ -32,5 +32,14 @@ "INTERACTION_DELAY": "0", "COLLAPSE_FEE_RATE": "0" } + }, + { + "name": "COLLATERAL_ETH", + "value": { + "SYNTHS": ["sUSD"], + "MIN_CRATIO": "1200000000000000000", + "MIN_COLLATERAL": "100000000000000000", + "ISSUE_FEE_RATE": "0" + } } ] diff --git a/publish/deployed/mainnet-ovm/config.json b/publish/deployed/mainnet-ovm/config.json index c9b42bcc8f..913ffbe2d9 100644 --- a/publish/deployed/mainnet-ovm/config.json +++ b/publish/deployed/mainnet-ovm/config.json @@ -160,5 +160,8 @@ }, "OwnerRelayOnOptimism": { "deploy": false + }, + "CollateralEth": { + "deploy": false } } diff --git a/publish/deployed/mainnet-ovm/deployment.json b/publish/deployed/mainnet-ovm/deployment.json index 4dc25e311c..38be0e7262 100644 --- a/publish/deployed/mainnet-ovm/deployment.json +++ b/publish/deployed/mainnet-ovm/deployment.json @@ -209,11 +209,11 @@ }, "Synthetix": { "name": "Synthetix", - "address": "0xff4287311138ad3BD051F84524B2eA3A682944a5", + "address": "0x20eBfbdD14c9D8093E9AC33e736Ac61bbaC90092", "source": "MintableSynthetix", - "link": "https://explorer.optimism.io/address/0xff4287311138ad3BD051F84524B2eA3A682944a5", - "timestamp": "2021-10-12T21:03:08.000Z", - "txn": "https://explorer.optimism.io/tx/0xb45b1bb22fc0a0abb33a4ff5d8c46c95379ed89a09d077918607d2de963ccc22", + "link": "https://explorer.optimism.io/address/0x20eBfbdD14c9D8093E9AC33e736Ac61bbaC90092", + "timestamp": "2021-12-15T21:06:22.000Z", + "txn": "https://explorer.optimism.io/tx/0x21e75db0194e9bdd96e9e37c701d72e5f973f9c8bfca82d474fd4e7c79314f50", "network": "mainnet" }, "ProxySynthetix": { @@ -512,6 +512,15 @@ "timestamp": "2021-11-23T23:07:05.000Z", "txn": "https://explorer.optimism.io/tx/0x8b3f33579f65c9d5f4a1eaf78fff47b6e42d481b9686575303be4f5bc6c30433", "network": "mainnet" + }, + "CollateralEth": { + "name": "CollateralEth", + "address": "0x308AD16ef90fe7caCb85B784A603CB6E71b1A41a", + "source": "CollateralEth", + "link": "https://explorer.optimism.io/address/0x308AD16ef90fe7caCb85B784A603CB6E71b1A41a", + "timestamp": "2021-12-15T21:06:22.000Z", + "txn": "https://explorer.optimism.io/tx/0x7849ba45a602863e4d20a0abd2d0e7d7d9ca6b5b369da56356b91f382a7e034a", + "network": "mainnet" } }, "sources": { @@ -14292,7 +14301,7 @@ } }, "MintableSynthetix": { - "bytecode": "60806040523480156200001c57600080620000196200039d565b50505b506040516200579538038062005795833981810160405260a08110156200004d576000806200004a6200039d565b50505b8101908080519291906020018051929190602001805192919060200180519291906020018051925086915085905084848480858560405160408082018152601782527f53796e746865746978204e6574776f726b20546f6b656e0000000000000000006020830152516040808201905260038152620a69cb60eb1b60208201528660128986816001600160a01b038116620001395760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015260640160405180910390620001366200039d565b50505b806000600181620001496200040a565b816001600160a01b0302191690836001600160a01b03160217906200016d6200046c565b5050507fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c6000826040516001600160a01b039283168152911660208201526040908101905180910390a15060008080620001c66200040a565b906101000a90046001600160a01b03166001600160a01b03161415620002315760405162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b6044820152606401604051809103906200022e6200039d565b50505b806002600181620002416200040a565b816001600160a01b0302191690836001600160a01b0316021790620002656200046c565b5050507ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e816040516001600160a01b03909116815260200160405180910390a150856005600181620002b66200040a565b816001600160a01b0302191690836001600160a01b0316021790620002da6200046c565b505050846006908051620002f3929160200190620004bb565b50600784805162000309929160200190620004bb565b5082806008620003186200046c565b50505081600960006101000a816200032f6200040a565b8160ff021916908360ff16021790620003476200046c565b5050505050505050505080600960016101000a81620003656200040a565b816001600160a01b0302191690836001600160a01b0316021790620003896200046c565b505050505050505050505050505062000597565b632a2a7adb598160e01b8152600481016020815285602082015260005b86811015620003d7578086015182820160400152602001620003ba565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b604081101562000467576000828201526020016200044e565b505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b6000815260206200044e565b8280620004c76200040a565b600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200051257805160ff191683800117856200050a6200046c565b505062000558565b82800160010185620005236200046c565b5050821562000558579182015b828111156200055857825182620005466200046c565b50509160200191906001019062000530565b50620005669291506200056a565b5090565b6200059491905b80821115620005665760008082620005886200046c565b50505060010162000571565b90565b6151ee80620005a76000396000f3fe608060405234801561001957600080610016614d0c565b50505b50600436106104055760003560e01c8063741853601161021e578063a9059cbb1161012e578063d8a1f76f116100c1578063e8e09b8b11610090578063e8e09b8b14610e23578063e90dd9e214610e58578063ec55688914610e60578063edef719a14610e68578063ee52a2f314610e9d57610405565b8063d8a1f76f14610d89578063dbf6334014610daf578063dd62ed3e14610db7578063e6203ed114610dee57610405565b8063c2bf3880116100fd578063c2bf388014610cd6578063c836fa0a14610d0b578063d37c4d8b14610d4c578063d67bdd2514610d8157610405565b8063a9059cbb14610c2f578063ace88afd14610c64578063af086c7e14610c9f578063bc67f83214610ca757610405565b80639324cac7116101b1578063987757dd11610180578063987757dd14610b745780639cbdaeb614610b9a5780639f76980714610ba2578063a311c7c214610bd1578063a5fdc5de14610c0057610405565b80639324cac714610b2d57806395d89b4114610b3557806397107d6d14610b3d5780639741fb2214610b6c57610405565b8063899ffef4116101ed578063899ffef414610aa85780638a29001414610ab05780638da5cb5b14610ad657806391e56b6814610ade57610405565b80637418536014610a4c57806379ba509714610a54578063835e119c14610a5c57806383d625d414610a8257610405565b80632c955fa7116103195780634e99bda9116102ac5780636ac0bf9c1161027b5780636ac0bf9c146109095780636c00f310146109385780636f01a9861461098757806370a08231146109c257806372cb051f146109f157610405565b80634e99bda91461087d57806353a47bb7146108855780635af090ef1461088d578063666ed4f1146108d457610405565b8063313ce567116102e8578063313ce567146107fa578063320223db1461080257806332608039146108315780633e89b9e51461085757610405565b80632c955fa71461072e5780632d3169eb1461075d5780632e0f26251461079557806330ead760146107b357610405565b80631627540c1161039c5780631fce304d1161036b5780631fce304d1461069357806323b872dd146106b9578063295da87d146106f85780632a9053181461071e5780632af64bd31461072657610405565b80631627540c1461062557806316b2213f1461065457806318160ddd14610683578063188214001461068b57610405565b80630e30963c116103d85780630e30963c146105405780631137aedf146105995780631249c58b146105ec578063131b0ae7146105f457610405565b806304f3bcec1461041357806305b3c1c91461043757806306fdde0314610478578063095ea7b3146104f7575b600080610410614d0c565b50505b61041b610ecf565b6040516001600160a01b03909116815260200160405180910390f35b6104666004803603602081101561045657600080610453614d0c565b50505b50356001600160a01b0316610eee565b60405190815260200160405180910390f35b610480610fad565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156104bc5780820151838201526020016104a4565b50505050905090810190601f1680156104e95780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61052c6004803603604081101561051657600080610513614d0c565b50505b506001600160a01b038135169060200135611066565b604051901515815260200160405180910390f35b6105786004803603608081101561055f5760008061055c614d0c565b50505b5080359060208101359060408101359060600135611164565b6040519182526001600160a01b031660208201526040908101905180910390f35b6105c8600480360360208110156105b8576000806105b5614d0c565b50505b50356001600160a01b0316611178565b60405180848152602001838152602001828152602001935050505060405180910390f35b61052c611252565b6106236004803603602081101561061357600080610610614d0c565b50505b50356001600160a01b031661125f565b005b6106236004803603602081101561064457600080610641614d0c565b50505b50356001600160a01b031661129d565b6104666004803603602081101561067357600080610670614d0c565b50505b50356001600160a01b0316611317565b61046661136a565b610480611377565b61052c600480360360208110156106b2576000806106af614d0c565b50505b50356113ae565b61052c600480360360608110156106d8576000806106d5614d0c565b50505b506001600160a01b03813581169160208101359091169060400135611493565b6106236004803603602081101561071757600080610714614d0c565b50505b50356114df565b6104806115aa565b61052c6115c7565b6106236004803603602081101561074d5760008061074a614d0c565b50505b50356001600160a01b0316611756565b6106236004803603608081101561077c57600080610779614d0c565b50505b50803590602081013590604081013590606001356117dc565b61079d611961565b60405160ff909116815260200160405180910390f35b610466600480360360a08110156107d2576000806107cf614d0c565b50505b508035906020810135906040810135906001600160a01b036060820135169060800135611966565b61079d611ae7565b610623600480360360208110156108215760008061081e614d0c565b50505b50356001600160a01b0316611b00565b61041b600480360360208110156108505760008061084d614d0c565b50505b5035611b33565b6104666004803603602081101561087657600080610873614d0c565b50505b5035611b7e565b61052c611bd2565b61041b611c7a565b610466600480360360a08110156108ac576000806108a9614d0c565b50505b508035906020810135906040810135906001600160a01b036060820135169060800135611c86565b610623600480360360408110156108f3576000806108f0614d0c565b50505b506001600160a01b038135169060200135611c99565b6104666004803603602081101561092857600080610925614d0c565b50505b50356001600160a01b0316611caf565b610623600480360360c081101561095757600080610954614d0c565b50505b506001600160a01b03813581169160208101359160408201359160608101359160808201359160a0013516611e49565b610623600480360360608110156109a6576000806109a3614d0c565b50505b506001600160a01b038135169060208101359060400135611fee565b610466600480360360208110156109e1576000806109de614d0c565b50505b50356001600160a01b0316612171565b6109f96121d7565b60405160208082528190810183818151815260200191508051906020019060200280838360005b83811015610a38578082015183820152602001610a20565b505050509050019250505060405180910390f35b610623612332565b610623612562565b61041b60048036036020811015610a7b57600080610a78614d0c565b50505b50356126e5565b61046660048036036020811015610aa157600080610a9e614d0c565b50505b5035612730565b6109f9612784565b61062360048036036020811015610acf57600080610acc614d0c565b50505b5035612804565b61041b612836565b610466600480360360c0811015610afd57600080610afa614d0c565b50505b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a00135612841565b61046661298b565b610480612996565b61062360048036036020811015610b5c57600080610b59614d0c565b50505b50356001600160a01b0316612a38565b610623612ab3565b6105c860048036036020811015610b9357600080610b90614d0c565b50505b5035612b76565b61041b612c33565b61062360048036036020811015610bc157600080610bbe614d0c565b50505b50356001600160a01b0316612c3f565b61046660048036036020811015610bf057600080610bed614d0c565b50505b50356001600160a01b0316612c83565b61046660048036036020811015610c1f57600080610c1c614d0c565b50505b50356001600160a01b0316612cd6565b61052c60048036036040811015610c4e57600080610c4b614d0c565b50505b506001600160a01b038135169060200135612d29565b61062360048036036060811015610c8357600080610c80614d0c565b50505b506001600160a01b038135169060208101359060400135612d91565b610623612e0e565b61062360048036036020811015610cc657600080610cc3614d0c565b50505b50356001600160a01b0316612e40565b61062360048036036040811015610cf557600080610cf2614d0c565b50505b506001600160a01b038135169060200135612e56565b61046660048036036080811015610d2a57600080610d27614d0c565b50505b506001600160a01b038135169060208101359060408101359060600135612f23565b61046660048036036040811015610d6b57600080610d68614d0c565b50505b506001600160a01b03813516906020013561306e565b61041b613134565b61062360048036036020811015610da857600080610da5614d0c565b50505b5035613140565b61046661320e565b61046660048036036040811015610dd657600080610dd3614d0c565b50505b506001600160a01b038135811691602001351661324b565b61052c60048036036040811015610e0d57600080610e0a614d0c565b50505b506001600160a01b0381351690602001356132b9565b61062360048036036040811015610e4257600080610e3f614d0c565b50505b506001600160a01b0381351690602001356132c3565b61041b6132f6565b61041b613302565b61062360048036036040811015610e8757600080610e84614d0c565b50505b506001600160a01b03813516906020013561330e565b61046660048036036060811015610ebc57600080610eb9614d0c565b50505b50803590602081013590604001356134d4565b60016009610edb614d77565b906101000a90046001600160a01b031681565b6000610ef8613672565b6001600160a01b03166305b3c1c9836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b158015610f5657600080610f53614d0c565b50505b505a610f60614e1e565b5050505050158015610f7f573d6000803e3d6000610f7c614d0c565b50505b505050506040513d6020811015610f9e57600080610f9b614d0c565b50505b81019080805195945050505050565b600680610fb8614d77565b600181600116156101000203166002900480601f016020809104026020016040519081016040528181529190602083018280610ff2614d77565b6001816001161561010002031660029004801561105e5780601f1061102c57610100808361101e614d77565b04028352916020019161105e565b820191906000526020600020905b81611043614d77565b8152906001019060200180831161103a57829003601f168201915b505050505081565b600061107061368b565b600080600461107d614d77565b906101000a90046001600160a01b03169050600560009061109c614d77565b906101000a90046001600160a01b03166001600160a01b031663da46098c8286866040516001600160e01b031960e086901b1681526001600160a01b03938416600482015291909216602482015260448101919091526064016000604051808303816000878061110a614dd2565b15801561111f5760008061111c614d0c565b50505b505a611129614f09565b505050505050158015611149573d6000803e3d6000611146614d0c565b50505b50505050611158818585613761565b60019150505b92915050565b60008061116f613844565b94509492505050565b6000806000611185613672565b6001600160a01b0316631137aedf856040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160606040518083038186806111ce614dd2565b1580156111e3576000806111e0614d0c565b50505b505a6111ed614e1e565b505050505015801561120c573d6000803e3d6000611209614d0c565b50505b505050506040513d606081101561122b57600080611228614d0c565b50505b81019080805192919060200180519291906020018051949993985093965091945050505050565b600061125c613844565b90565b611267613896565b806003600181611275614d77565b816001600160a01b0302191690836001600160a01b0316021790611297614fcf565b50505050565b6112a5613896565b80600180806112b2614d77565b816001600160a01b0302191690836001600160a01b03160217906112d4614fcf565b5050507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22816040516001600160a01b03909116815260200160405180910390a150565b6000611321613672565b6001600160a01b03166316b2213f836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b6008611374614d77565b81565b60405160408082019052601781527f53796e746865746978204e6574776f726b20546f6b656e000000000000000000602082015281565b6000806113b961390e565b6001600160a01b031663059c29ec600060046113d3614d77565b906101000a90046001600160a01b0316856040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303818680611423614dd2565b15801561143857600080611435614d0c565b50505b505a611442614e1e565b5050505050158015611461573d6000803e3d600061145e614d0c565b50505b505050506040513d60208110156114805760008061147d614d0c565b50505b8101908080519390931195945050505050565b600061149d61368b565b6114a5613925565b6114af848361399b565b506114d7600060046114bf614d77565b906101000a90046001600160a01b0316858585613cb0565b949350505050565b6114e7613de2565b6114ef61368b565b6114f7613672565b6001600160a01b031663b06e8c6560006004611511614d77565b906101000a90046001600160a01b0316836040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780611563614dd2565b15801561157857600080611575614d0c565b50505b505a611582614f09565b5050505050501580156115a2573d6000803e3d600061159f614d0c565b50505b505050505b50565b6040516040808201905260038152620a69cb60eb1b602082015281565b600060606115d3612784565b905060005b815181101561174d5760008282815181106115ef57fe5b60200260200101516000818152600a60205290915060409020600090611613614d77565b6001600160a01b036101009290920a90041660016009611631614d77565b906101000a90046001600160a01b03166001600160a01b03166321f8a721836040516001600160e01b031960e084901b16815260048101919091526024016020604051808303818680611682614dd2565b15801561169757600080611694614d0c565b50505b505a6116a1614e1e565b50505050501580156116c0573d6000803e3d60006116bd614d0c565b50505b505050506040513d60208110156116df576000806116dc614d0c565b50505b8101908080516001600160a01b031693909314159250829150611733905057506000818152600a60205260408120600090611718614d77565b906101000a90046001600160a01b03166001600160a01b0316145b15611744576000935050505061125c565b506001016115d8565b50600191505090565b61175e613de2565b61176661368b565b61176e613672565b6001600160a01b0316632b3f41aa8260006004611789614d77565b906101000a90046001600160a01b03166040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160006040518083038160008780611563614dd2565b6117e4613e1d565b600060026117f0614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff9784848460405160200180848152602001838152602001828152602001935050505060405160208183030381529060405260026040518060316150c1823960310190506040518091039020886000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156118cc5780820151838201526020016118b4565b50505050905090810190601f1680156118f95780820380516001836020036101000a031916815260200191505b5097505050505050505060006040518083038160008780611918614dd2565b15801561192d5760008061192a614d0c565b50505b505a611937614f09565b505050505050158015611957573d6000803e3d6000611954614d0c565b50505b5050505050505050565b601281565b600085846119748282613e97565b61197c61368b565b61198461390e565b6001600160a01b0316634f8633d26000600461199e614d77565b906101000a90046001600160a01b031660046000906119bb614d77565b906101000a90046001600160a01b03168b8b8b60046000906119db614d77565b906101000a90046001600160a01b031660008d8d6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e482015261010481019190915261012401604080518083038160008780611a6a614dd2565b158015611a7f57600080611a7c614d0c565b50505b505a611a89614f09565b505050505050158015611aa9573d6000803e3d6000611aa6614d0c565b50505b505050506040513d6040811015611ac857600080611ac5614d0c565b50505b810190808051929190602001805150929b9a5050505050505050505050565b60006009611af3614d77565b906101000a900460ff1681565b611b08613de2565b611b1061368b565b611b18613672565b6001600160a01b031663fd864ccf8260006004611789614d77565b6000611b3d613672565b6001600160a01b03166332608039836040516001600160e01b031960e084901b16815260048101919091526024016020604051808303818680610f41614dd2565b6000611b88613672565b6001600160a01b0316637b1001b78360016040516001600160e01b031960e085901b1681526004810192909252151560248201526044016020604051808303818680610f41614dd2565b6000611bdc613672565b6001600160a01b0316634e99bda96040518163ffffffff1660e01b81526004016020604051808303818680611c0f614dd2565b158015611c2457600080611c21614d0c565b50505b505a611c2e614e1e565b5050505050158015611c4d573d6000803e3d6000611c4a614d0c565b50505b505050506040513d6020811015611c6c57600080611c69614d0c565b50505b810190808051935050505090565b60006001610edb614d77565b6000611c90613844565b95945050505050565b611ca1613f21565b611cab8282613f9b565b5050565b6000611cb9613672565b6001600160a01b0316636bed04158360006005611cd4614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231866040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680611d2d614dd2565b158015611d4257600080611d3f614d0c565b50505b505a611d4c614e1e565b5050505050158015611d6b573d6000803e3d6000611d68614d0c565b50505b505050506040513d6020811015611d8a57600080611d87614d0c565b50505b81019080805192506040915050516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160408051808303818680611dd3614dd2565b158015611de857600080611de5614d0c565b50505b505a611df2614e1e565b5050505050158015611e11573d6000803e3d6000611e0e614d0c565b50505b505050506040513d6040811015611e3057600080611e2d614d0c565b50505b8101908080519291906020018051509295945050505050565b611e51613e1d565b60006002611e5d614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff9786868686866040516020810195909552604080860194909452606085019290925260808401526001600160a01b031660a083015260c09091019051602081830303815290604052600260405180603e6150f28239603e0190506040518091039020611ee58b61419d565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015611f58578082015183820152602001611f40565b50505050905090810190601f168015611f855780820380516001836020036101000a031916815260200191505b5097505050505050505060006040518083038160008780611fa4614dd2565b158015611fb957600080611fb6614d0c565b50505b505a611fc3614f09565b505050505050158015611954573d6000803e3d6000611fe0614d0c565b505050505050505050505050565b611ff6613e1d565b60006002612002614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff978383604051602001808381526020018281526020019250505060405160208183030381529060405260026040518060276151a682396027019050604051809103902061206b8861419d565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156120de5780820151838201526020016120c6565b50505050905090810190601f16801561210b5780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303816000878061212a614dd2565b15801561213f5760008061213c614d0c565b50505b505a612149614f09565b50505050505015801561159f573d6000803e3d6000612166614d0c565b505050505050505050565b600080600561217e614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b60606121e1613672565b6001600160a01b03166372cb051f6040518163ffffffff1660e01b81526004016000604051808303818680612214614dd2565b15801561222957600080612226614d0c565b50505b505a612233614e1e565b5050505050158015612252573d6000803e3d600061224f614d0c565b50505b505050506040513d6000823e601f3d908101601f19168201604052602081101561228457600080612281614d0c565b50505b81019080805160405193929190846401000000008211156122ad576000806122aa614d0c565b50505b9083019060208201858111156122cb576000806122c8614d0c565b50505b82518660208202830111640100000000821117156122f1576000806122ee614d0c565b50505b825250602001908051906020019060200280838360005b83811015612320578082015183820152602001612308565b50505050905001604052505050905090565b606061233c612784565b905060005b8151811015611cab57600082828151811061235857fe5b60200260200101519050600060016009612370614d77565b906101000a90046001600160a01b03166001600160a01b031663dacb2d0183846040517f5265736f6c766572206d697373696e67207461726765743a2000000000000000602082015260398101919091526059016040516020818303038152906040526040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561242557808201518382015260200161240d565b50505050905090810190601f1680156124525780820380516001836020036101000a031916815260200191505b509350505050602060405180830381868061246b614dd2565b1580156124805760008061247d614d0c565b50505b505a61248a614e1e565b50505050501580156124a9573d6000803e3d60006124a6614d0c565b50505b505050506040513d60208110156124c8576000806124c5614d0c565b50505b8101908080516000868152600a602052909450849350604092509050206001816124f0614d77565b816001600160a01b0302191690836001600160a01b0316021790612512614fcf565b5050507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa6882826040519182526001600160a01b031660208201526040908101905180910390a15050600101612341565b6000600161256e614d77565b906101000a90046001600160a01b03166001600160a01b03165a61259061501d565b6001600160a01b0316146125de5760405162461bcd60e51b815260040180806020018281038252603581526020018061506460359139604001915050604051809103906125db614d0c565b50505b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c60008061260a614d77565b906101000a90046001600160a01b03166001600090612627614d77565b906101000a90046001600160a01b03166040516001600160a01b039283168152911660208201526040908101905180910390a160006001612666614d77565b906101000a90046001600160a01b03166000806101000a81612686614d77565b816001600160a01b0302191690836001600160a01b03160217906126a8614fcf565b5050506000600160006101000a816126be614d77565b816001600160a01b0302191690836001600160a01b03160217906126e0614fcf565b505050565b60006126ef613672565b6001600160a01b031663835e119c836040516001600160e01b031960e084901b16815260048101919091526024016020604051808303818680610f41614dd2565b600061273a613672565b6001600160a01b0316637b1001b78360006040516001600160e01b031960e085901b1681526004810192909252151560248201526044016020604051808303818680610f41614dd2565b60608061278f6141a9565b9050606060016040519080825280602002602001820160405280156127be578160200160208202803883390190505b5090507453796e746865746978427269646765546f4261736560581b816000815181106127e757fe5b6020026020010181815250506127fd82826142a9565b9250505090565b61280c613de2565b61281461368b565b61281c613672565b6001600160a01b031663042e068860006004611511614d77565b600080610edb614d77565b6000858461284f8282613e97565b61285761368b565b61285f61390e565b6001600160a01b0316634f8633d28a6000600461287a614d77565b906101000a90046001600160a01b03168b8b8b8f60008d8d6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e48201526101048101919091526101240160408051808303816000878061290d614dd2565b1580156129225760008061291f614d0c565b50505b505a61292c614f09565b50505050505015801561294c573d6000803e3d6000612949614d0c565b50505b505050506040513d604081101561296b57600080612968614d0c565b50505b810190808051929190602001805150929c9b505050505050505050505050565b631cd554d160e21b81565b6007806129a1614d77565b600181600116156101000203166002900480601f0160208091040260200160405190810160405281815291906020830182806129db614d77565b6001816001161561010002031660029004801561105e5780601f10612a0757610100808361101e614d77565b820191906000526020600020905b81612a1e614d77565b81529060010190602001808311612a155750859350505050565b612a40613896565b806002600181612a4e614d77565b816001600160a01b0302191690836001600160a01b0316021790612a70614fcf565b5050507ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e816040516001600160a01b03909116815260200160405180910390a150565b612abb613de2565b612ac361368b565b612acb613672565b6001600160a01b031663497d704a60006004612ae5614d77565b906101000a90046001600160a01b03166040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160006040518083038160008780612b31614dd2565b158015612b4657600080612b43614d0c565b50505b505a612b50614f09565b505050505050158015611297573d6000803e3d6000612b6d614d0c565b5050505050505b565b6000806000612b8361368b565b612b8b61390e565b6001600160a01b0316631b16802c60006004612ba5614d77565b906101000a90046001600160a01b0316866040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160606040518083038160008780612bf7614dd2565b158015612c0c57600080612c09614d0c565b50505b505a612c16614f09565b50505050505015801561120c573d6000803e3d6000611209614d0c565b60006003610edb614d77565b612c47614365565b806005600181612c55614d77565b816001600160a01b0302191690836001600160a01b0316021790612c77614fcf565b5050506115a7816144f0565b6000612c8d613672565b6001600160a01b031663a311c7c2836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b6000612ce0613672565b6001600160a01b031663a5fdc5de836040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680610f41614dd2565b6000612d3361368b565b612d3b613925565b612d6060006004612d4a614d77565b906101000a90046001600160a01b03168361399b565b50612d8760006004612d70614d77565b906101000a90046001600160a01b03168484614638565b5060019392505050565b612d99613e1d565b60006002612da5614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff9783836040516020018083815260200182815260200192505050604051602081830303815290604052600260405180602861509982396028019050604051809103902061206b8861419d565b612e16613de2565b612e1e61368b565b612e26613672565b6001600160a01b031663c897713260006004612ae5614d77565b612e48614645565b806004600181611275614d77565b612e5e613de2565b612e6661368b565b612e6e613672565b6001600160a01b0316639a5154b48360006004612e89614d77565b906101000a90046001600160a01b0316846040516001600160e01b031960e086901b1681526001600160a01b039384166004820152919092166024820152604481019190915260640160006040518083038160008780612ee7614dd2565b158015612efc57600080612ef9614d0c565b50505b505a612f06614f09565b505050505050158015612b6d573d6000803e3d6000611957614d0c565b60008382612f318282613e97565b612f3961368b565b612f4161390e565b6001600160a01b0316634f8633d28860006004612f5c614d77565b906101000a90046001600160a01b03168989898d60008f6000801b6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e482015261010481019190915261012401604080518083038160008780612ff2614dd2565b15801561300757600080613004614d0c565b50505b505a613011614f09565b505050505050158015613031573d6000803e3d600061302e614d0c565b50505b505050506040513d60408110156130505760008061304d614d0c565b50505b810190808051929190602001805150929a9950505050505050505050565b6000613078613672565b6001600160a01b031663d37c4d8b84846040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160206040518083038186806130c7614dd2565b1580156130dc576000806130d9614d0c565b50505b505a6130e6614e1e565b5050505050158015613105573d6000803e3d6000613102614d0c565b50505b505050506040513d602081101561312457600080613121614d0c565b50505b8101908080519695505050505050565b60006004610edb614d77565b613148613f21565b6000613152614712565b905061315e8183613f9b565b806001600160a01b03166359974e38836040516001600160e01b031960e084901b1681526004810191909152602401602060405180830381600087806131a2614dd2565b1580156131b7576000806131b4614d0c565b50505b505a6131c1614f09565b5050505050501580156131e1573d6000803e3d60006131de614d0c565b50505b505050506040513d6020811015613200576000806131fd614d0c565b50505b810190808051505050505050565b6000613218613672565b6001600160a01b031663dbf633406040518163ffffffff1660e01b81526004016020604051808303818680611c0f614dd2565b6000806005613258614d77565b906101000a90046001600160a01b03166001600160a01b031663dd62ed3e84846040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186806130c7614dd2565b600061115e613844565b6132cb613de2565b6132d361368b565b6132db613672565b6001600160a01b03166344ec6b628360006004612e89614d77565b60006005610edb614d77565b60006002610edb614d77565b613316613f21565b61331e613925565b6000600561332a614d77565b6001600160a01b036101009290920a90041663b46310f68361341f8460006005613352614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231886040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186806133ab614dd2565b1580156133c0576000806133bd614d0c565b50505b505a6133ca614e1e565b50505050501580156133e9573d6000803e3d60006133e6614d0c565b50505b505050506040513d602081101561340857600080613405614d0c565b50505b8101908080519392505063ffffffff614733169050565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780613460614dd2565b15801561347557600080613472614d0c565b50505b505a61347f614f09565b50505050505015801561349f573d6000803e3d600061349c614d0c565b50505b505050506134af82600083614798565b6134c98160086134bd614d77565b9063ffffffff61473316565b8060086115a2614fcf565b600083826134e28282613e97565b6134ea61368b565b6134f261390e565b6001600160a01b0316634f8633d26000600461350c614d77565b906101000a90046001600160a01b03166004600090613529614d77565b906101000a90046001600160a01b03168989896004600090613549614d77565b906101000a90046001600160a01b031660006004600090613568614d77565b906101000a90046001600160a01b03166000801b6040516001600160e01b031960e08c901b1681526001600160a01b03998a1660048201529789166024890152604488019690965260648701949094526084860192909252851660a4850152151560c484015290921660e4820152610104810191909152610124016040805180830381600087806135f7614dd2565b15801561360c57600080613609614d0c565b50505b505a613616614f09565b505050505050158015613636573d6000803e3d6000613633614d0c565b50505b505050506040513d604081101561365557600080613652614d0c565b50505b810190808051929190602001805150929998505050505050505050565b60006136866524b9b9bab2b960d11b614805565b905090565b60006002613697614d77565b906101000a90046001600160a01b03166001600160a01b03165a6136b961501d565b6001600160a01b0316141580156137055750600060036136d7614d77565b906101000a90046001600160a01b03166001600160a01b03165a6136f961501d565b6001600160a01b031614155b801561374657505a61371561501d565b6001600160a01b03166000600461372a614d77565b906101000a90046001600160a01b03166001600160a01b031614155b15612b74575a61375461501d565b60046001816126be614d77565b6000600261376d614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff97826040516020018082815260200191505060405160208183030381529060405260036040518060216151858239602101905060405180910390206137ce8861419d565b6137d78861419d565b60006040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018481526020018360001b8152602001828103825288818151815260200191508051602090910190808383600083156120de5780820151838201526020016120c6565b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f742062652072756e206f6e2074686973206c617965720000000000604482015260640160405180910390611cab614d0c565b6000806138a1614d77565b906101000a90046001600160a01b03166001600160a01b03165a6138c361501d565b6001600160a01b031614612b745760405162461bcd60e51b815260040180806020018281038252602f815260200180615156602f913960400191505060405180910390611cab614d0c565b60006136866822bc31b430b733b2b960b91b614805565b61392d614906565b6001600160a01b031663086dabd16040518163ffffffff1660e01b81526004016000604051808303818680613960614dd2565b15801561397557600080613972614d0c565b50505b505a61397f614e1e565b5050505050158015611297573d6000803e3d6000612b6d614d0c565b6000806139a6614920565b6001600160a01b0316638b3f8088856040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401604080518083038186806139ee614dd2565b158015613a0357600080613a00614d0c565b50505b505a613a0d614e1e565b5050505050158015613a2c573d6000803e3d6000613a29614d0c565b50505b505050506040513d6040811015613a4b57600080613a48614d0c565b50505b8101908080519291906020018051509293505082159150611158905057600080613a73613672565b6001600160a01b0316636bed04158760006005613a8e614d77565b906101000a90046001600160a01b03166001600160a01b03166370a082318a6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680613ae7614dd2565b158015613afc57600080613af9614d0c565b50505b505a613b06614e1e565b5050505050158015613b25573d6000803e3d6000613b22614d0c565b50505b505050506040513d6020811015613b4457600080613b41614d0c565b50505b81019080805192506040915050516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160408051808303818680613b8d614dd2565b158015613ba257600080613b9f614d0c565b50505b505a613bac614e1e565b5050505050158015613bcb573d6000803e3d6000613bc8614d0c565b50505b505050506040513d6040811015613bea57600080613be7614d0c565b50505b810190808051929190602001805193955092935050505081851115613c495760405162461bcd60e51b81526004018080602001828103825260268152602001806151306026913960400191505060405180910390613c46614d0c565b50505b8015613ca45760405162461bcd60e51b815260206004820152601e60248201527f412073796e7468206f7220534e58207261746520697320696e76616c69640000604482015260640160405180910390613ca1614d0c565b50505b50600195945050505050565b6000806005613cbd614d77565b6001600160a01b036101009290920a90041663da46098c8587613d478660006005613ce6614d77565b906101000a90046001600160a01b03166001600160a01b031663dd62ed3e8b8d6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160206040518083038186806133ab614dd2565b6040516001600160e01b031960e086901b1681526001600160a01b039384166004820152919092166024820152604481019190915260640160006040518083038160008780613d94614dd2565b158015613da957600080613da6614d0c565b50505b505a613db3614f09565b505050505050158015613dd3573d6000803e3d6000613dd0614d0c565b50505b50505050611c9084848461493c565b613dea614906565b6001600160a01b0316637c3125416040518163ffffffff1660e01b81526004016000604051808303818680613960614dd2565b613e2561390e565b6001600160a01b03165a613e3761501d565b6001600160a01b031614612b745760405162461bcd60e51b815260206004820152601e60248201527f4f6e6c792045786368616e6765722063616e20696e766f6b6520746869730000604482015260640160405180910390611cab614d0c565b613e9f614906565b6001600160a01b0316631ce00ba283836040516001600160e01b031960e085901b168152600481019290925260248201526044016000604051808303818680613ee6614dd2565b158015613efb57600080613ef8614d0c565b50505b505a613f05614e1e565b5050505050158015612b6d573d6000803e3d6000611957614d0c565b613f29614c80565b6001600160a01b03165a613f3b61501d565b6001600160a01b031614612b745760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c7920626520696e766f6b656420627920627269646765000000604482015260640160405180910390611cab614d0c565b60006005613fa7614d77565b6001600160a01b036101009290920a90041663b46310f68361409c8460006005613fcf614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231886040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680614028614dd2565b15801561403d5760008061403a614d0c565b50505b505a614047614e1e565b5050505050158015614066573d6000803e3d6000614063614d0c565b50505b505050506040513d602081101561408557600080614082614d0c565b50505b8101908080519392505063ffffffff614ca3169050565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087806140dd614dd2565b1580156140f2576000806140ef614d0c565b50505b505a6140fc614f09565b50505050505015801561411c573d6000803e3d6000614119614d0c565b50505b505050506141835a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b604081101561417957600082820152602001614162565b5050508383614798565b6134c9816008614191614d77565b9063ffffffff614ca316565b6001600160a01b031690565b606060056040519080825280602002602001820160405280156141d6578160200160208202803883390190505b5090506d53796e746865746978537461746560901b816000815181106141f857fe5b6020026020010181815250506b53797374656d53746174757360a01b8160018151811061422157fe5b6020026020010181815250506822bc31b430b733b2b960b91b8160028151811061424757fe5b6020026020010181815250506524b9b9bab2b960d11b8160038151811061426a57fe5b602002602001018181525050722932bbb0b93239a234b9ba3934b13aba34b7b760691b8160048151811061429a57fe5b60200260200101818152505090565b606081518351016040519080825280602002602001820160405280156142d9578160200160208202803883390190505b50905060005b835181101561431b578381815181106142f457fe5b602002602001015182828151811061430857fe5b60209081029190910101526001016142df565b5060005b825181101561435e5782818151811061433457fe5b602002602001015182828651018151811061434b57fe5b602090810291909101015260010161431f565b5092915050565b60006002614371614d77565b906101000a90046001600160a01b03166001600160a01b03165a61439361501d565b6001600160a01b0316141580156143df5750600060036143b1614d77565b906101000a90046001600160a01b03166001600160a01b03165a6143d361501d565b6001600160a01b031614155b801561442057505a6143ef61501d565b6001600160a01b031660006004614404614d77565b906101000a90046001600160a01b03166001600160a01b031614155b15614461575a61442e61501d565b600460018161443b614d77565b816001600160a01b0302191690836001600160a01b031602179061445d614fcf565b5050505b60008061446c614d77565b6001600160a01b036101009290920a9004166000600461448a614d77565b906101000a90046001600160a01b03166001600160a01b031614612b745760405162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015260640160405180910390611cab614d0c565b600060026144fc614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff97826040516001600160a01b0390911660208201526040908101905160208183030381529060405260016040517f546f6b656e5374617465557064617465642861646472657373290000000000008152601a01604051809103902060008060006040518763ffffffff1660e01b815260040180806020018781526020018681526020018560001b81526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b838110156145ec5780820151838201526020016145d4565b50505050905090810190601f1680156146195780820380516001836020036101000a031916815260200191505b5097505050505050505060006040518083038160008780611563614dd2565b60006114d784848461493c565b60006002614651614d77565b906101000a90046001600160a01b03166001600160a01b03165a61467361501d565b6001600160a01b031614806146bc57506000600361468f614d77565b906101000a90046001600160a01b03166001600160a01b03165a6146b161501d565b6001600160a01b0316145b612b745760405162461bcd60e51b815260206004820152601760248201527f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000604482015260640160405180910390611cab614d0c565b6000613686722932bbb0b93239a234b9ba3934b13aba34b7b760691b614805565b6000828211156147925760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f77000060448201526064016040518091039061478f614d0c565b50505b50900390565b600060026147a4614d77565b906101000a90046001600160a01b03166001600160a01b031663907dff97826040516020018082815260200191505060405160208183030381529060405260036040518060216151cd8239602101905060405180910390206137ce8861419d565b6000818152600a602052806040812060009061481f614d77565b6001600160a01b036101009290920a90041690508015158360405170026b4b9b9b4b7339030b2323932b9b99d1607d1b602082015260318101919091526051016040516020818303038152906040529061435e5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156148bc5780820151838201526020016148a4565b50505050905090810190601f1680156148e95780820380516001836020036101000a031916815260200191505b5092505050604051809103906148fd614d0c565b50505092915050565b60006136866b53797374656d53746174757360a01b614805565b60006136866d53796e746865746978537461746560901b614805565b60006001600160a01b038316158015906149c057505a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b60408110156149a757600082820152602001614990565b5050506001600160a01b0316836001600160a01b031614155b80156149f95750600060026149d3614d77565b906101000a90046001600160a01b03166001600160a01b0316836001600160a01b031614155b614a525760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220746f2074686973206164647265737300604482015260640160405180910390614a4f614d0c565b50505b60006005614a5e614d77565b6001600160a01b036101009290920a90041663b46310f685614adf8560006005614a86614d77565b906101000a90046001600160a01b03166001600160a01b03166370a082318a6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186806133ab614dd2565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780614b20614dd2565b158015614b3557600080614b32614d0c565b50505b505a614b3f614f09565b505050505050158015614b5f573d6000803e3d6000614b5c614d0c565b50505b505050506005600090614b70614d77565b6001600160a01b036101009290920a90041663b46310f684614bf18560006005614b98614d77565b906101000a90046001600160a01b03166001600160a01b03166370a08231896040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303818680614028614dd2565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160006040518083038160008780614c32614dd2565b158015614c4757600080614c44614d0c565b50505b505a614c51614f09565b505050505050158015614c71573d6000803e3d6000614c6e614d0c565b50505b50505050612d87848484614798565b60006136867453796e746865746978427269646765546f4261736560581b614805565b600082820183811015614d055760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640160405180910390614d02614d0c565b50505b9392505050565b632a2a7adb598160e01b8152600481016020815285602082015260005b86811015614d44578086015182820160400152602001614d29565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b60408110156126e057600082820152602001614dbb565b638435035b598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b80516000825293506020614dbb565b638540661f598160e01b8152614e4f565b808083111561115e575090919050565b808083101561115e575090919050565b836004820152846024820152606060448201528660648201526084810160005b88811015614e87578088015182820152602001614e6f565b506060828960a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8b8b82606087013350600060045af15059614edc8d3d614e3f565b8c01614ee88187614e2f565b5b82811015614efd5760008152602001614ee9565b50929c50505050505050565b6385979f76598160e01b8152836004820152846024820152606060448201528760648201526084810160005b89811015614f4d578089015182820152602001614f35565b506060828a60a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8c8c82606087013350600060045af15059614fa28e3d614e3f565b8d01614fae8187614e2f565b5b82811015614fc35760008152602001614faf565b50929d50505050505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b600081526020614dbb565b6373509064598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b80516000825293506020614dbb56fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e65727368697045786368616e67655265636c61696d28616464726573732c627974657333322c75696e743235362945786368616e6765547261636b696e6728627974657333322c627974657333322c75696e743235362c75696e743235362953796e746845786368616e676528616464726573732c627974657333322c75696e743235362c627974657333322c75696e743235362c616464726573732943616e6e6f74207472616e73666572207374616b6564206f7220657363726f77656420534e584f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e417070726f76616c28616464726573732c616464726573732c75696e743235362945786368616e676552656261746528616464726573732c627974657333322c75696e74323536295472616e7366657228616464726573732c616464726573732c75696e7432353629", + "bytecode": "60806040523480156200001157600080fd5b50604051620042f7380380620042f7833981810160405260a08110156200003757600080fd5b508051602080830151604080850151606086015160809096015182518084018452601781527f53796e746865746978204e6574776f726b20546f6b656e00000000000000000081870152835180850190945260038452620a69cb60eb1b958401959095529495929490939091869186918691869186918291879187918660128986816001600160a01b03811662000115576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1506000546001600160a01b0316620001c0576040805162461bcd60e51b815260206004820152601160248201527013dddb995c881b5d5cdd081899481cd95d607a1b604482015290519081900360640190fd5b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9181900360200190a150600480546001600160a01b0319166001600160a01b038816179055845162000242906005906020880190620002ab565b50835162000258906006906020870190620002ab565b50506007919091556008805460ff191660ff90921691909117610100600160a81b0319166101006001600160a01b0397909716969096029590951790945550620003509c50505050505050505050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002ee57805160ff19168380011785556200031e565b828001600101855582156200031e579182015b828111156200031e57825182559160200191906001019062000301565b506200032c92915062000330565b5090565b6200034d91905b808211156200032c576000815560010162000337565b90565b613f9780620003606000396000f3fe608060405234801561001057600080fd5b50600436106103f15760003560e01c80637418536011610215578063ace88afd11610125578063d8a1f76f116100b8578063e8e09b8b11610087578063e8e09b8b14610c94578063e90dd9e214610cc0578063ec55688914610cc8578063edef719a14610cd0578063ee52a2f314610cfc576103f1565b8063d8a1f76f14610c15578063dbf6334014610c32578063dd62ed3e14610c3a578063e6203ed114610c68576103f1565b8063c62e5df8116100f4578063c62e5df814610b7a578063c836fa0a14610ba9578063d37c4d8b14610be1578063d67bdd2514610c0d576103f1565b8063ace88afd14610aee578063af086c7e14610b20578063bc67f83214610b28578063c2bf388014610b4e576103f1565b80639324cac7116101a8578063987757dd11610177578063987757dd14610a335780639f76980714610a50578063a311c7c214610a76578063a5fdc5de14610a9c578063a9059cbb14610ac2576103f1565b80639324cac7146109f557806395d89b41146109fd57806397107d6d14610a055780639741fb2214610a2b576103f1565b8063899ffef4116101e4578063899ffef4146109825780638a2900141461098a5780638da5cb5b146109a757806391e56b68146109af576103f1565b8063741853601461093857806379ba509714610940578063835e119c1461094857806383d625d414610965576103f1565b80632c955fa7116103105780634e99bda9116102a35780636ac0bf9c116102725780636ac0bf9c1461081c5780636c00f310146108425780636f01a9861461088857806370a08231146108ba57806372cb051f146108e0576103f1565b80634e99bda9146107a257806353a47bb7146107aa5780635af090ef146107b2578063666ed4f1146107f0576103f1565b8063313ce567116102df578063313ce5671461073a578063320223db1461074257806332608039146107685780633e89b9e514610785576103f1565b80632c955fa7146106895780632d3169eb146106af5780632e0f2625146106de57806330ead760146106fc576103f1565b806316b2213f1161038857806323b872dd1161035757806323b872dd14610626578063295da87d1461065c5780632a905318146106795780632af64bd314610681576103f1565b806316b2213f146105d357806318160ddd146105f957806318821400146106015780631fce304d14610609576103f1565b80630e30963c116103c45780630e30963c1461050f5780631137aedf1461055f5780631249c58b146105a35780631627540c146105ab576103f1565b806304f3bcec146103f657806305b3c1c91461041a57806306fdde0314610452578063095ea7b3146104cf575b600080fd5b6103fe610d25565b604080516001600160a01b039092168252519081900360200190f35b6104406004803603602081101561043057600080fd5b50356001600160a01b0316610d39565b60408051918252519081900360200190f35b61045a610dca565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049457818101518382015260200161047c565b50505050905090810190601f1680156104c15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104fb600480360360408110156104e557600080fd5b506001600160a01b038135169060200135610e58565b604080519115158252519081900360200190f35b61053e6004803603608081101561052557600080fd5b5080359060208101359060408101359060600135610ef3565b604080519283526001600160a01b0390911660208301528051918290030190f35b6105856004803603602081101561057557600080fd5b50356001600160a01b0316610f07565b60408051938452602084019290925282820152519081900360600190f35b6104fb610fad565b6105d1600480360360208110156105c157600080fd5b50356001600160a01b0316610fba565b005b610440600480360360208110156105e957600080fd5b50356001600160a01b0316611016565b610440611075565b61045a61107b565b6104fb6004803603602081101561061f57600080fd5b50356110b4565b6104fb6004803603606081101561063c57600080fd5b506001600160a01b03813581169160208101359091169060400135611147565b6105d16004803603602081101561067257600080fd5b5035611184565b61045a61120e565b6104fb61122d565b6105d16004803603602081101561069f57600080fd5b50356001600160a01b031661133e565b6105d1600480360360808110156106c557600080fd5b50803590602081013590604081013590606001356113ad565b6106e66114f0565b6040805160ff9092168252519081900360200190f35b610440600480360360a081101561071257600080fd5b508035906020810135906040810135906001600160a01b0360608201351690608001356114f5565b6106e66115d3565b6105d16004803603602081101561075857600080fd5b50356001600160a01b03166115dc565b6103fe6004803603602081101561077e57600080fd5b503561164b565b6104406004803603602081101561079b57600080fd5b5035611698565b6104fb6116f2565b6103fe611765565b610440600480360360a08110156107c857600080fd5b508035906020810135906040810135906001600160a01b036060820135169060800135611774565b6105d16004803603604081101561080657600080fd5b506001600160a01b038135169060200135611787565b6104406004803603602081101561083257600080fd5b50356001600160a01b031661179d565b6105d1600480360360c081101561085857600080fd5b506001600160a01b03813581169160208101359160408201359160608101359160808201359160a001351661189f565b6105d16004803603606081101561089e57600080fd5b506001600160a01b0381351690602081013590604001356119fe565b610440600480360360208110156108d057600080fd5b50356001600160a01b0316611b3f565b6108e8611b92565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561092457818101518382015260200161090c565b505050509050019250505060405180910390f35b6105d1611ca2565b6105d1611e7b565b6103fe6004803603602081101561095e57600080fd5b5035611f37565b6104406004803603602081101561097b57600080fd5b5035611f84565b6108e8611fde565b6105d1600480360360208110156109a057600080fd5b5035612052565b6103fe6120bf565b610440600480360360c08110156109c557600080fd5b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a001356120ce565b6104406121b1565b61045a6121bc565b6105d160048036036020811015610a1b57600080fd5b50356001600160a01b0316612217565b6105d1612273565b61058560048036036020811015610a4957600080fd5b50356122f5565b6105d160048036036020811015610a6657600080fd5b50356001600160a01b0316612375565b61044060048036036020811015610a8c57600080fd5b50356001600160a01b03166123a1565b61044060048036036020811015610ab257600080fd5b50356001600160a01b0316612400565b6104fb60048036036040811015610ad857600080fd5b506001600160a01b03813516906020013561245f565b6105d160048036036060811015610b0457600080fd5b506001600160a01b03813516906020810135906040013561249f565b6105d16124ff565b6105d160048036036020811015610b3e57600080fd5b50356001600160a01b0316612566565b6105d160048036036040811015610b6457600080fd5b506001600160a01b038135169060200135612590565b61044060048036036080811015610b9057600080fd5b5080359060208101359060408101359060600135612622565b61044060048036036080811015610bbf57600080fd5b506001600160a01b03813516906020810135906040810135906060013561262c565b61044060048036036040811015610bf757600080fd5b506001600160a01b03813516906020013561270a565b6103fe6127a4565b6105d160048036036020811015610c2b57600080fd5b50356127b3565b610440612841565b61044060048036036040811015610c5057600080fd5b506001600160a01b0381358116916020013516612883565b6104fb60048036036040811015610c7e57600080fd5b506001600160a01b0381351690602001356128de565b6105d160048036036040811015610caa57600080fd5b506001600160a01b0381351690602001356129c1565b6103fe612a37565b6103fe612a46565b6105d160048036036040811015610ce657600080fd5b506001600160a01b038135169060200135612a55565b61044060048036036060811015610d1257600080fd5b5080359060208101359060400135612b8a565b60085461010090046001600160a01b031681565b6000610d43612c68565b6001600160a01b03166305b3c1c9836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b505afa158015610dac573d6000803e3d6000fd5b505050506040513d6020811015610dc257600080fd5b505192915050565b6005805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610e505780601f10610e2557610100808354040283529160200191610e50565b820191906000526020600020905b815481529060010190602001808311610e3357829003601f168201915b505050505081565b6000610e62612c81565b6003546004805460408051633691826360e21b81526001600160a01b03948516938101849052878516602482015260448101879052905192939091169163da46098c9160648082019260009290919082900301818387803b158015610ec657600080fd5b505af1158015610eda573d6000803e3d6000fd5b50505050610ee9818585612cc0565b5060019392505050565b600080610efe612d8a565b94509492505050565b6000806000610f14612c68565b6001600160a01b0316631137aedf856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060606040518083038186803b158015610f6957600080fd5b505afa158015610f7d573d6000803e3d6000fd5b505050506040513d6060811015610f9357600080fd5b508051602082015160409092015190969195509350915050565b6000610fb7612d8a565b90565b610fc2612dd7565b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b6000611020612c68565b6001600160a01b03166316b2213f836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b60075481565b6040518060400160405280601781526020017f53796e746865746978204e6574776f726b20546f6b656e00000000000000000081525081565b6000806110bf612e20565b600354604080516301670a7b60e21b81526001600160a01b039283166004820152602481018790529051929091169163059c29ec91604480820192602092909190829003018186803b15801561111457600080fd5b505afa158015611128573d6000803e3d6000fd5b505050506040513d602081101561113e57600080fd5b50511192915050565b6000611151612c81565b611159612e37565b6111638483612e8b565b5060035461117c906001600160a01b03168585856130bf565b949350505050565b61118c6131b7565b611194612c81565b61119c612c68565b6003546040805163b06e8c6560e01b81526001600160a01b039283166004820152602481018590529051929091169163b06e8c659160448082019260009290919082900301818387803b1580156111f257600080fd5b505af1158015611206573d6000803e3d6000fd5b505050505b50565b604051806040016040528060038152602001620a69cb60eb1b81525081565b60006060611239611fde565b905060005b815181101561133557600082828151811061125557fe5b6020908102919091018101516000818152600983526040908190205460085482516321f8a72160e01b81526004810185905292519395506001600160a01b0391821694610100909104909116926321f8a721926024808201939291829003018186803b1580156112c457600080fd5b505afa1580156112d8573d6000803e3d6000fd5b505050506040513d60208110156112ee57600080fd5b50516001600160a01b031614158061131b57506000818152600960205260409020546001600160a01b0316155b1561132c5760009350505050610fb7565b5060010161123e565b50600191505090565b6113466131b7565b61134e612c81565b611356612c68565b6003546040805163159fa0d560e11b81526001600160a01b038581166004830152928316602482015290519290911691632b3f41aa9160448082019260009290919082900301818387803b1580156111f257600080fd5b6113b56131f7565b6002805460408051602081018790528082018690526060808201869052825180830390910181526080909101918290526001600160a01b039092169263907dff979291806031613e04823960310190506040518091039020886000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015611481578181015183820152602001611469565b50505050905090810190601f1680156114ae5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b1580156114d257600080fd5b505af11580156114e6573d6000803e3d6000fd5b5050505050505050565b601281565b600085846115038282613264565b61150b612c81565b611513612e20565b600354604080516327c319e960e11b81526001600160a01b039283166004820181905260248201819052604482018d9052606482018c9052608482018b905260a4820152600060c4820181905289841660e4830152610104820189905282519490931693634f8633d29361012480840194938390030190829087803b15801561159b57600080fd5b505af11580156115af573d6000803e3d6000fd5b505050506040513d60408110156115c557600080fd5b505198975050505050505050565b60085460ff1681565b6115e46131b7565b6115ec612c81565b6115f4612c68565b6003546040805163fd864ccf60e01b81526001600160a01b03858116600483015292831660248201529051929091169163fd864ccf9160448082019260009290919082900301818387803b1580156111f257600080fd5b6000611655612c68565b6001600160a01b03166332608039836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610d9857600080fd5b60006116a2612c68565b6001600160a01b0316637b1001b78360016040518363ffffffff1660e01b815260040180838152602001821515151581526020019250505060206040518083038186803b158015610d9857600080fd5b60006116fc612c68565b6001600160a01b0316634e99bda96040518163ffffffff1660e01b815260040160206040518083038186803b15801561173457600080fd5b505afa158015611748573d6000803e3d6000fd5b505050506040513d602081101561175e57600080fd5b5051905090565b6001546001600160a01b031681565b600061177e612d8a565b95945050505050565b61178f6132cb565b6117998282613338565b5050565b60006117a7612c68565b60048054604080516370a0823160e01b81526001600160a01b0387811694820194909452905193831693636bed041593879316916370a08231916024808301926020929190829003018186803b15801561180057600080fd5b505afa158015611814573d6000803e3d6000fd5b505050506040513d602081101561182a57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091528051604480840193829003018186803b15801561187557600080fd5b505afa158015611889573d6000803e3d6000fd5b505050506040513d6040811015610dc257600080fd5b6118a76131f7565b60028054604080516020810189905280820188905260608101879052608081018690526001600160a01b0385811660a0808401919091528351808403909101815260c0909201928390529092169263907dff97929180603e613e358239603e019050604051809103902061191a8b613455565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b8381101561198d578181015183820152602001611975565b50505050905090810190601f1680156119ba5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b1580156119de57600080fd5b505af11580156119f2573d6000803e3d6000fd5b50505050505050505050565b611a066131f7565b6002805460408051602081018690528082018590528151808203830181526060909101918290526001600160a01b039092169263907dff979291806027613ee9823960270190506040518091039020611a5e88613455565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b8152602001828103825288818151815260200191508051906020019080838360005b83811015611ad1578181015183820152602001611ab9565b50505050905090810190601f168015611afe5780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b158015611b2257600080fd5b505af1158015611b36573d6000803e3d6000fd5b50505050505050565b60048054604080516370a0823160e01b81526001600160a01b03858116948201949094529051600093909216916370a0823191602480820192602092909190829003018186803b158015610d9857600080fd5b6060611b9c612c68565b6001600160a01b03166372cb051f6040518163ffffffff1660e01b815260040160006040518083038186803b158015611bd457600080fd5b505afa158015611be8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015611c1157600080fd5b8101908080516040519392919084640100000000821115611c3157600080fd5b908301906020820185811115611c4657600080fd5b8251866020820283011164010000000082111715611c6357600080fd5b82525081516020918201928201910280838360005b83811015611c90578181015183820152602001611c78565b50505050905001604052505050905090565b6060611cac611fde565b905060005b8151811015611799576000828281518110611cc857fe5b602002602001015190506000600860019054906101000a90046001600160a01b03166001600160a01b031663dacb2d01838460405160200180807f5265736f6c766572206d697373696e67207461726765743a20000000000000008152506019018281526020019150506040516020818303038152906040526040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611d93578181015183820152602001611d7b565b50505050905090810190601f168015611dc05780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b158015611dde57600080fd5b505afa158015611df2573d6000803e3d6000fd5b505050506040513d6020811015611e0857600080fd5b505160008381526009602090815260409182902080546001600160a01b0319166001600160a01b03851690811790915582518681529182015281519293507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68929081900390910190a15050600101611cb1565b6001546001600160a01b03163314611ec45760405162461bcd60e51b8152600401808060200182810382526035815260200180613da76035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000611f41612c68565b6001600160a01b031663835e119c836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610d9857600080fd5b6000611f8e612c68565b6001600160a01b0316637b1001b78360006040518363ffffffff1660e01b815260040180838152602001821515151581526020019250505060206040518083038186803b158015610d9857600080fd5b606080611fe9613461565b60408051600180825281830190925291925060609190602080830190803883390190505090507453796e746865746978427269646765546f4261736560581b8160008151811061203557fe5b60200260200101818152505061204b8282613554565b9250505090565b61205a6131b7565b612062612c81565b61206a612c68565b600354604080516285c0d160e31b81526001600160a01b039283166004820152602481018590529051929091169163042e06889160448082019260009290919082900301818387803b1580156111f257600080fd5b6000546001600160a01b031681565b600085846120dc8282613264565b6120e4612c81565b6120ec612e20565b600354604080516327c319e960e11b81526001600160a01b038d8116600483018190529381166024830152604482018d9052606482018c9052608482018b905260a4820193909352600060c4820181905289841660e4830152610104820189905282519490931693634f8633d29361012480840194938390030190829087803b15801561217857600080fd5b505af115801561218c573d6000803e3d6000fd5b505050506040513d60408110156121a257600080fd5b50519998505050505050505050565b631cd554d160e21b81565b6006805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610e505780601f10610e2557610100808354040283529160200191610e50565b61221f612dd7565b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517ffc80377ca9c49cc11ae6982f390a42db976d5530af7c43889264b13fbbd7c57e9181900360200190a150565b61227b6131b7565b612283612c81565b61228b612c68565b600354604080516324beb82560e11b81526001600160a01b0392831660048201529051929091169163497d704a9160248082019260009290919082900301818387803b1580156122da57600080fd5b505af11580156122ee573d6000803e3d6000fd5b505050505b565b6000806000612302612c81565b61230a612e20565b600354604080516306c5a00b60e21b81526001600160a01b0392831660048201526024810188905290519290911691631b16802c916044808201926060929091908290030181600087803b15801561236157600080fd5b505af1158015610f7d573d6000803e3d6000fd5b61237d613610565b600480546001600160a01b0319166001600160a01b03831617905561120b816136a9565b60006123ab612c68565b6001600160a01b031663a311c7c2836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b600061240a612c68565b6001600160a01b031663a5fdc5de836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610d9857600080fd5b6000612469612c81565b612471612e37565b600354612487906001600160a01b031683612e8b565b50600354610ee9906001600160a01b031684846137d4565b6124a76131f7565b6002805460408051602081018690528082018590528151808203830181526060909101918290526001600160a01b039092169263907dff979291806028613ddc823960280190506040518091039020611a5e88613455565b6125076131b7565b61250f612c81565b612517612c68565b6003546040805163644bb89960e11b81526001600160a01b0392831660048201529051929091169163c89771329160248082019260009290919082900301818387803b1580156122da57600080fd5b61256e6137e1565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6125986131b7565b6125a0612c81565b6125a8612c68565b60035460408051632694552d60e21b81526001600160a01b03868116600483015292831660248201526044810185905290519290911691639a5154b49160648082019260009290919082900301818387803b15801561260657600080fd5b505af115801561261a573d6000803e3d6000fd5b505050505050565b600061117c612d8a565b6000838261263a8282613264565b612642612c81565b61264a612e20565b600354604080516327c319e960e11b81526001600160a01b038b8116600483018190529381166024830152604482018b9052606482018a90526084820189905260a48201849052600060c4830181905260e483019490945261010482018490528251941693634f8633d29361012480840194938390030190829087803b1580156126d357600080fd5b505af11580156126e7573d6000803e3d6000fd5b505050506040513d60408110156126fd57600080fd5b5051979650505050505050565b6000612714612c68565b6001600160a01b031663d37c4d8b84846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b15801561277157600080fd5b505afa158015612785573d6000803e3d6000fd5b505050506040513d602081101561279b57600080fd5b50519392505050565b6003546001600160a01b031681565b6127bb6132cb565b60006127c5613840565b90506127d18183613338565b806001600160a01b03166359974e38836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561281757600080fd5b505af115801561282b573d6000803e3d6000fd5b505050506040513d60208110156122ee57600080fd5b600061284b612c68565b6001600160a01b031663dbf633406040518163ffffffff1660e01b815260040160206040518083038186803b15801561173457600080fd5b6004805460408051636eb1769f60e11b81526001600160a01b0386811694820194909452848416602482015290516000939092169163dd62ed3e91604480820192602092909190829003018186803b15801561277157600080fd5b60006128e8612e37565b6128f0612c81565b6000806128fb612c68565b6003546040805163298f137d60e21b81526001600160a01b0389811660048301526024820189905292831660448201528151939092169263a63c4df49260648082019392918290030181600087803b15801561295657600080fd5b505af115801561296a573d6000803e3d6000fd5b505050506040513d604081101561298057600080fd5b50805160209091015160035491935091506129a9908690849084906001600160a01b0316613861565b60035461177e9086906001600160a01b0316846137d4565b6129c96131b7565b6129d1612c81565b6129d9612c68565b6003546040805163227635b160e11b81526001600160a01b038681166004830152928316602482015260448101859052905192909116916344ec6b629160648082019260009290919082900301818387803b15801561260657600080fd5b6004546001600160a01b031681565b6002546001600160a01b031681565b612a5d6132cb565b612a65612e37565b60048054604080516370a0823160e01b81526001600160a01b03868116948201949094529051929091169163b46310f6918591612afd91869186916370a08231916024808301926020929190829003018186803b158015612ac557600080fd5b505afa158015612ad9573d6000803e3d6000fd5b505050506040513d6020811015612aef57600080fd5b50519063ffffffff61393816565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612b4c57600080fd5b505af1158015612b60573d6000803e3d6000fd5b50505050612b7082600083613995565b600754612b83908263ffffffff61393816565b6007555050565b60008382612b988282613264565b612ba0612c81565b612ba8612e20565b600354604080516327c319e960e11b81526001600160a01b039283166004820181905260248201819052604482018b9052606482018a90526084820189905260a48201819052600060c4830181905260e4830191909152610104820181905282519490931693634f8633d29361012480840194938390030190829087803b158015612c3257600080fd5b505af1158015612c46573d6000803e3d6000fd5b505050506040513d6040811015612c5c57600080fd5b50519695505050505050565b6000612c7c6524b9b9bab2b960d11b6139e8565b905090565b6002546001600160a01b03163314801590612ca757506003546001600160a01b03163314155b156122f357600380546001600160a01b03191633179055565b60025460408051602080820185905282518083039091018152908201918290526001600160a01b039092169163907dff9791600390806021613ec8823960210190506040518091039020612d1388613455565b612d1c88613455565b60006040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018481526020018360001b81526020018281038252888181518152602001915080519060200190808383600083811015611ad1578181015183820152602001611ab9565b6040805162461bcd60e51b815260206004820152601b60248201527f43616e6e6f742062652072756e206f6e2074686973206c617965720000000000604482015290519081900360640190fd5b6000546001600160a01b031633146122f35760405162461bcd60e51b815260040180806020018281038252602f815260200180613e99602f913960400191505060405180910390fd5b6000612c7c6822bc31b430b733b2b960b91b6139e8565b612e3f613ac5565b6001600160a01b031663086dabd16040518163ffffffff1660e01b815260040160006040518083038186803b158015612e7757600080fd5b505afa1580156122ee573d6000803e3d6000fd5b600080612e96613adf565b60408051631167f01160e31b81526001600160a01b0387811660048301528251931692638b3f808892602480840193919291829003018186803b158015612edc57600080fd5b505afa158015612ef0573d6000803e3d6000fd5b505050506040513d6040811015612f0657600080fd5b505190508015610ee957600080612f1b612c68565b60048054604080516370a0823160e01b81526001600160a01b038b811694820194909452905193831693636bed0415938b9316916370a08231916024808301926020929190829003018186803b158015612f7457600080fd5b505afa158015612f88573d6000803e3d6000fd5b505050506040513d6020811015612f9e57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091528051604480840193829003018186803b158015612fe957600080fd5b505afa158015612ffd573d6000803e3d6000fd5b505050506040513d604081101561301357600080fd5b5080516020909101519092509050818511156130605760405162461bcd60e51b8152600401808060200182810382526026815260200180613e736026913960400191505060405180910390fd5b80156130b3576040805162461bcd60e51b815260206004820152601e60248201527f412073796e7468206f7220534e58207261746520697320696e76616c69640000604482015290519081900360640190fd5b50600195945050505050565b6004805460408051636eb1769f60e11b81526001600160a01b0387811694820194909452878416602482015290516000939092169163da46098c918791899161312c918891879163dd62ed3e91604480820192602092909190829003018186803b158015612ac557600080fd5b6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050600060405180830381600087803b15801561319457600080fd5b505af11580156131a8573d6000803e3d6000fd5b5050505061177e848484613afb565b6131bf613ac5565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b158015612e7757600080fd5b6131ff612e20565b6001600160a01b0316336001600160a01b0316146122f3576040805162461bcd60e51b815260206004820152601e60248201527f4f6e6c792045786368616e6765722063616e20696e766f6b6520746869730000604482015290519081900360640190fd5b61326c613ac5565b6001600160a01b0316631ce00ba283836040518363ffffffff1660e01b8152600401808381526020018281526020019250505060006040518083038186803b1580156132b757600080fd5b505afa15801561261a573d6000803e3d6000fd5b6132d3613d22565b6001600160a01b0316336001600160a01b0316146122f3576040805162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c7920626520696e766f6b656420627920627269646765000000604482015290519081900360640190fd5b60048054604080516370a0823160e01b81526001600160a01b03868116948201949094529051929091169163b46310f69185916133d091869186916370a08231916024808301926020929190829003018186803b15801561339857600080fd5b505afa1580156133ac573d6000803e3d6000fd5b505050506040513d60208110156133c257600080fd5b50519063ffffffff613d4516565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561341f57600080fd5b505af1158015613433573d6000803e3d6000fd5b50505050613442308383613995565b600754612b83908263ffffffff613d4516565b6001600160a01b031690565b60408051600580825260c082019092526060916020820160a0803883390190505090506d53796e746865746978537461746560901b816000815181106134a357fe5b6020026020010181815250506b53797374656d53746174757360a01b816001815181106134cc57fe5b6020026020010181815250506822bc31b430b733b2b960b91b816002815181106134f257fe5b6020026020010181815250506524b9b9bab2b960d11b8160038151811061351557fe5b602002602001018181525050722932bbb0b93239a234b9ba3934b13aba34b7b760691b8160048151811061354557fe5b60200260200101818152505090565b60608151835101604051908082528060200260200182016040528015613584578160200160208202803883390190505b50905060005b83518110156135c65783818151811061359f57fe5b60200260200101518282815181106135b357fe5b602090810291909101015260010161358a565b5060005b8251811015613609578281815181106135df57fe5b60200260200101518282865101815181106135f657fe5b60209081029190910101526001016135ca565b5092915050565b6002546001600160a01b0316331480159061363657506003546001600160a01b03163314155b1561364e57600380546001600160a01b031916331790555b6000546003546001600160a01b039081169116146122f3576040805162461bcd60e51b815260206004820152601360248201527227bbb732b91037b7363c90333ab731ba34b7b760691b604482015290519081900360640190fd5b600254604080516001600160a01b038481166020808401919091528351808403820181528385018086527f546f6b656e5374617465557064617465642861646472657373290000000000009052935192839003605a01832063907dff9760e01b8452600160248501819052604485018290526000606486018190526084860181905260a4860181905260c060048701908152875160c48801528751959098169763907dff97979692959394919384938493839260e490920191908a0190808383885b8381101561378357818101518382015260200161376b565b50505050905090810190601f1680156137b05780820380516001836020036101000a031916815260200191505b50975050505050505050600060405180830381600087803b1580156111f257600080fd5b600061117c848484613afb565b6002546001600160a01b031633146122f3576040805162461bcd60e51b815260206004820152601760248201527f4f6e6c79207468652070726f78792063616e2063616c6c000000000000000000604482015290519081900360640190fd5b6000612c7c722932bbb0b93239a234b9ba3934b13aba34b7b760691b6139e8565b6002805460408051602081018790528082018690526001600160a01b03858116606080840191909152835180840390910181526080909201928390529092169263907dff979291806032613f108239603201905060405180910390206138c689613455565b6000806040518763ffffffff1660e01b815260040180806020018781526020018681526020018581526020018460001b81526020018360001b81526020018281038252888181518152602001915080519060200190808383600083811015611481578181015183820152602001611469565b60008282111561398f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60025460408051602080820185905282518083039091018152908201918290526001600160a01b039092169163907dff9791600390806021613f42823960210190506040518091039020612d1388613455565b600081815260096020908152604080832054815170026b4b9b9b4b7339030b2323932b9b99d1607d1b9381019390935260318084018690528251808503909101815260519093019091526001600160a01b031690816136095760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613a8a578181015183820152602001613a72565b50505050905090810190601f168015613ab75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6000612c7c6b53797374656d53746174757360a01b6139e8565b6000612c7c6d53796e746865746978537461746560901b6139e8565b60006001600160a01b03831615801590613b1e57506001600160a01b0383163014155b8015613b3857506002546001600160a01b03848116911614155b613b89576040805162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220746f2074686973206164647265737300604482015290519081900360640190fd5b60048054604080516370a0823160e01b81526001600160a01b03888116948201949094529051929091169163b46310f6918791613be991879186916370a08231916024808301926020929190829003018186803b158015612ac557600080fd5b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613c3857600080fd5b505af1158015613c4c573d6000803e3d6000fd5b505060048054604080516370a0823160e01b81526001600160a01b0389811694820194909452905192909116935063b46310f692508691613cb091879186916370a08231916024808301926020929190829003018186803b15801561339857600080fd5b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015613cff57600080fd5b505af1158015613d13573d6000803e3d6000fd5b50505050610ee9848484613995565b6000612c7c7453796e746865746978427269646765546f4261736560581b6139e8565b600082820183811015613d9f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b939250505056fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e65727368697045786368616e67655265636c61696d28616464726573732c627974657333322c75696e743235362945786368616e6765547261636b696e6728627974657333322c627974657333322c75696e743235362c75696e743235362953796e746845786368616e676528616464726573732c627974657333322c75696e743235362c627974657333322c75696e743235362c616464726573732943616e6e6f74207472616e73666572207374616b6564206f7220657363726f77656420534e584f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e417070726f76616c28616464726573732c616464726573732c75696e743235362945786368616e676552656261746528616464726573732c627974657333322c75696e74323536294163636f756e744c69717569646174656428616464726573732c75696e743235362c75696e743235362c61646472657373295472616e7366657228616464726573732c616464726573732c75696e7432353629a265627a7a7231582046b95ecf0aafa1112c0aa66ee1e9d26dc5fd4e44c0171b7a85c17e188b20e23964736f6c63430005100032", "abi": [ { "inputs": [ @@ -14326,6 +14335,37 @@ "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "snxRedeemed", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountLiquidated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "liquidator", + "type": "address" + } + ], + "name": "AccountLiquidated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -15083,6 +15123,42 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "exchangeAtomically", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { "constant": false, "inputs": [ @@ -15239,7 +15315,7 @@ "outputs": [ { "internalType": "uint256", - "name": "amountReceived", + "name": "", "type": "uint256" } ], @@ -15288,21 +15364,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "constant": true, - "inputs": [], - "name": "integrationProxy", - "outputs": [ - { - "internalType": "contract Proxy", - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, { "constant": true, "inputs": [], @@ -15403,12 +15464,12 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "account", "type": "address" }, { "internalType": "uint256", - "name": "", + "name": "susdAmount", "type": "uint256" } ], @@ -15670,21 +15731,6 @@ "stateMutability": "view", "type": "function" }, - { - "constant": false, - "inputs": [ - { - "internalType": "address payable", - "name": "_integrationProxy", - "type": "address" - } - ], - "name": "setIntegrationProxy", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, { "constant": false, "inputs": [ @@ -15970,15 +16016,15 @@ } ], "source": { - "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749", + "keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a", "urls": [ - "bzz-raw://45f229865baabb02bd1d2fc70e2689e8eddb335483c56fbc8a40aa839725831c", - "dweb:/ipfs/QmZ7hK15fu8JkDQRbHzVCHgyKLL6P7VJeuGEaUEY7ZHpom" + "bzz-raw://8eeb6e102aeb9e33d5bc3feafa27ced0cbf46166b8642b55711ae8088cbef77d", + "dweb:/ipfs/QmWnq7ZBagWFnHz4o82gyM193MZqeD5bqNiZxtd8R23N5D" ] }, "metadata": { "compiler": { - "version": "0.5.16-develop.2020.12.10+ovm+commit.25adf37d" + "version": "0.5.16+commit.9c3226ce" }, "language": "Solidity", "settings": { @@ -15995,10 +16041,10 @@ }, "sources": { "MintableSynthetix.sol": { - "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749", + "keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a", "urls": [ - "bzz-raw://45f229865baabb02bd1d2fc70e2689e8eddb335483c56fbc8a40aa839725831c", - "dweb:/ipfs/QmZ7hK15fu8JkDQRbHzVCHgyKLL6P7VJeuGEaUEY7ZHpom" + "bzz-raw://8eeb6e102aeb9e33d5bc3feafa27ced0cbf46166b8642b55711ae8088cbef77d", + "dweb:/ipfs/QmWnq7ZBagWFnHz4o82gyM193MZqeD5bqNiZxtd8R23N5D" ] } }, @@ -29712,6 +29758,1207 @@ }, "version": 1 } + }, + "CollateralEth": { + "bytecode": "6080604052600d805460ff191660011790553480156200001e57600080fd5b506040516200476938038062004769833981016040819052620000419162000150565b8585858585858380876001600160a01b0381166200007c5760405162461bcd60e51b8152600401620000739062000261565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0383161781556040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91620000c99184906200023b565b60405180910390a150600280546001600160a01b039283166001600160a01b0319918216179091556006805498909216971696909617909555600492909255600a55600b5550506001600e5550620002e295505050505050565b80516200013081620002b2565b92915050565b80516200013081620002cc565b80516200013081620002d7565b60008060008060008060c087890312156200016a57600080fd5b600062000178898962000123565b96505060206200018b89828a0162000143565b95505060406200019e89828a0162000123565b9450506060620001b189828a0162000136565b9350506080620001c489828a0162000136565b92505060a0620001d789828a0162000136565b9150509295509295509295565b620001ef81620002a5565b82525050565b620001ef816200027c565b60006200020f60198362000273565b7f4f776e657220616464726573732063616e6e6f74206265203000000000000000815260200192915050565b604081016200024b8285620001e4565b6200025a6020830184620001f5565b9392505050565b60208082528101620001308162000200565b90815260200190565b6000620001308262000299565b90565b600062000130826200027c565b6001600160a01b031690565b600062000130826200028c565b620002bd816200027c565b8114620002c957600080fd5b50565b620002bd8162000289565b620002bd816200028c565b61447780620002f26000396000f3fe60806040526004361061020f5760003560e01c806372e18b6a11610118578063925ead11116100a0578063ba2de9bc1161006f578063ba2de9bc146105b0578063d2b8035a146105c5578063de81eda9146105e5578063e1ec3c6814610605578063f3f437031461063a5761020f565b8063925ead1114610546578063a76cdfa51461055b578063aa2d8ce31461057b578063b562a1ab1461059b5761020f565b8063846321a4116100e7578063846321a4146104af578063899ffef4146104cf5780638cd2e0c7146104f15780638da5cb5b1461051157806390abb4d9146105265761020f565b806372e18b6a14610445578063741853601461046557806379ba50971461047a5780637e1323551461048f5761020f565b8063379607f51161019b578063441a3e701161016a578063441a3e70146103bb57806347e7ef24146103db578063481c6a75146103ee57806353a47bb7146104035780635eb2ad01146104255761020f565b8063379607f51461034657806338245377146103665780634065b81b1461038657806341c738011461039b5761020f565b80631627540c116101e25780631627540c146102af57806323d60e2e146102cf5780632af64bd3146102ef57806330edd96114610311578063361e2086146103315761020f565b806304f3bcec1461021457806306c19e3f1461023f5780630710285c1461025f5780630aebeb4e14610281575b600080fd5b34801561022057600080fd5b5061022961065a565b6040516102369190614009565b60405180910390f35b61025261024d3660046136c0565b610669565b6040516102369190613f97565b34801561026b57600080fd5b5061027f61027a36600461355b565b61067f565b005b34801561028d57600080fd5b506102a161029c366004613684565b6106c5565b604051610236929190613fb3565b3480156102bb57600080fd5b5061027f6102ca3660046134e5565b61070e565b3480156102db57600080fd5b5061027f6102ea3660046135a8565b61076c565b3480156102fb57600080fd5b5061030461083b565b6040516102369190613f89565b34801561031d57600080fd5b5061025261032c366004613684565b610953565b34801561033d57600080fd5b50610252610971565b34801561035257600080fd5b5061027f610361366004613684565b610977565b34801561037257600080fd5b50610252610381366004613684565b610a4c565b34801561039257600080fd5b50610304610a5e565b3480156103a757600080fd5b506102526103b6366004613684565b610a67565b3480156103c757600080fd5b506102a16103d63660046136c0565b610b7f565b6102a16103e9366004613521565b610bca565b3480156103fa57600080fd5b50610229610be3565b34801561040f57600080fd5b50610418610bf2565b6040516102369190613f26565b34801561043157600080fd5b5061027f610440366004613521565b610c01565b34801561045157600080fd5b506103046104603660046135a8565b610c37565b34801561047157600080fd5b5061027f610cfb565b34801561048657600080fd5b5061027f610e4d565b34801561049b57600080fd5b506102526104aa3660046136c0565b610ee9565b3480156104bb57600080fd5b5061027f6104ca366004613684565b610f2e565b3480156104db57600080fd5b506104e4610f6b565b6040516102369190613f78565b3480156104fd57600080fd5b506102a161050c36600461355b565b6110fb565b34801561051d57600080fd5b50610418611116565b34801561053257600080fd5b5061027f610541366004613618565b611125565b34801561055257600080fd5b50610252611171565b34801561056757600080fd5b5061027f610576366004613684565b611177565b34801561058757600080fd5b50610252610596366004613684565b6111b4565b3480156105a757600080fd5b50610252611278565b3480156105bc57600080fd5b5061025261127e565b3480156105d157600080fd5b506102a16105e03660046136c0565b611284565b3480156105f157600080fd5b50610418610600366004613684565b611291565b34801561061157600080fd5b50610625610620366004613684565b6112ac565b604051610236999897969594939291906141ee565b34801561064657600080fd5b506102526106553660046134e5565b611306565b6002546001600160a01b031681565b60006106783484846000611318565b9392505050565b600061068c8484846119c0565b336000908152600f60205260409020549091506106af908263ffffffff611d2716565b336000908152600f602052604090205550505050565b6000806106d23384611d4c565b336000908152600f602052604090205491935091506106f7908263ffffffff611d2716565b336000908152600f60205260409020559092909150565b610716611e42565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290610761908390613f26565b60405180910390a150565b610774611e42565b82811461079c5760405162461bcd60e51b815260040161079390614048565b60405180910390fd5b60005b8381101561082c5760008585838181106107b557fe5b600780546001810182556000918252602090920293909301357fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909101819055925082916008915086868681811061080957fe5b60209081029290920135835250810191909152604001600020555060010161079f565b50610835610cfb565b50505050565b60006060610847610f6b565b905060005b815181101561094957600082828151811061086357fe5b602090810291909101810151600081815260039092526040918290205460025492516321f8a72160e01b81529193506001600160a01b039081169216906321f8a721906108b4908590600401613f97565b60206040518083038186803b1580156108cc57600080fd5b505afa1580156108e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109049190810190613503565b6001600160a01b031614158061092f57506000818152600360205260409020546001600160a01b0316155b156109405760009350505050610950565b5060010161084c565b5060019150505b90565b6007818154811061096057fe5b600091825260209091200154905081565b600c5481565b600e805460010190819055336000908152600f60205260409020546109a2908363ffffffff611e6e16565b336000818152600f602052604080822093909355915184906109c390613f1b565b60006040518083038185875af1925050503d8060008114610a00576040519150601f19603f3d011682016040523d82523d6000602084013e610a05565b606091505b5050905080610a265760405162461bcd60e51b815260040161079390614058565b50600e548114610a485760405162461bcd60e51b815260040161079390614168565b5050565b60086020526000908152604090205481565b600d5460ff1681565b6000610a71613407565b506000828152600560208181526040928390208351610120810185528154815260018201546001600160a01b03169281019290925260028101549382019390935260038301546060820152600483015460808201529082015460ff16151560a0820152600682015460c0820152600782015460e0820152600890910154610100820152610afc611e96565b6001600160a01b031663fbfeca4082600a546004546040518463ffffffff1660e01b8152600401610b2f939291906141a5565b60206040518083038186803b158015610b4757600080fd5b505afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061067891908101906136a2565b600080610b8c8484611eb7565b336000908152600f60205260409020549193509150610bb1908463ffffffff611d2716565b336000908152600f602052604090205590939092509050565b600080610bd8848434611f5c565b909590945092505050565b6006546001600160a01b031681565b6001546001600160a01b031681565b610c09611e42565b600090815260096020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b6007546000908414610c4b57506000610cf3565b60005b84811015610ced576000868683818110610c6457fe5b9050602002013590508060078381548110610c7b57fe5b906000526020600020015414610c9657600092505050610cf3565b60078281548110610ca357fe5b906000526020600020015460086000878786818110610cbe57fe5b9050602002013581526020019081526020016000205414610ce457600092505050610cf3565b50600101610c4e565b50600190505b949350505050565b6060610d05610f6b565b905060005b8151811015610a48576000828281518110610d2157fe5b602002602001015190506000600260009054906101000a90046001600160a01b03166001600160a01b031663dacb2d018384604051602001610d639190613f10565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d8f929190613fc1565b60206040518083038186803b158015610da757600080fd5b505afa158015610dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ddf9190810190613503565b6000838152600360205260409081902080546001600160a01b0319166001600160a01b038416179055519091507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa6890610e3b9084908490613fa5565b60405180910390a15050600101610d0a565b6001546001600160a01b03163314610e775760405162461bcd60e51b815260040161079390614038565b6000546001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c92610eba926001600160a01b0391821692911690613f4f565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000610ef3611e96565b6001600160a01b0316638a7399758484600a546004546040518563ffffffff1660e01b8152600401610b2f94939291906142da565b92915050565b610f36611e42565b600b8190556040517fd19fe8ad9152af12b174a60210fb798db0767d63973ebb97298dc44d67a5c82d90610761908390613f97565b606080610f7661202d565b60408051600680825260e08201909252919250606091906020820160c08038833901905050905066119959541bdbdb60ca1b81600081518110610fb557fe5b6020026020010181815250506c45786368616e6765526174657360981b81600181518110610fdf57fe5b6020026020010181815250506822bc31b430b733b2b960b91b8160028151811061100557fe5b6020026020010181815250506b53797374656d53746174757360a01b8160038151811061102e57fe5b6020026020010181815250506814de5b9d1a1cd554d160ba1b8160048151811061105457fe5b6020026020010181815250506d10dbdb1b185d195c985b155d1a5b60921b8160058151811061107f57fe5b6020026020010181815250506060611097838361207e565b90506110f38160078054806020026020016040519081016040528092919081815260200182805480156110e957602002820191906000526020600020905b8154815260200190600101908083116110d5575b505050505061207e565b935050505090565b60008061110a8533868661213a565b90969095509350505050565b6000546001600160a01b031681565b61112d611e42565b600d805460ff191682151517908190556040517f261991749e1b2436706a31bde8bf184bb37fe21e303709b78d3b881afacadaa2916107619160ff90911690613f89565b600a5481565b61117f611e42565b600c8190556040517fe7bd72551c54d568cd97b00dc52d2787b5c5d4f0070d3582c1e8ba25141f799c90610761908390613f97565b60006111be613407565b506000828152600560208181526040928390208351610120810185528154815260018201546001600160a01b03169281019290925260028101549382019390935260038301546060820152600483015460808201529082015460ff16151560a0820152600682015460c0820152600782015460e0820152600890910154610100820152611249611e96565b6001600160a01b031663e99f9647826004546040518363ffffffff1660e01b8152600401610b2f929190614188565b60045481565b600b5481565b600080610bd884846122e9565b6009602052600090815260409020546001600160a01b031681565b600560208190526000918252604090912080546001820154600283015460038401546004850154958501546006860154600787015460089097015495976001600160a01b0390951696939592949360ff9092169290919089565b600f6020526000908152604090205481565b600061132261272b565b61132a6127cd565b600d5460ff1661134c5760405162461bcd60e51b815260040161079390614118565b6000838152600860205260409020546113775760405162461bcd60e51b815260040161079390614068565b61137f612821565b6001600160a01b0316632528f0fe846040518263ffffffff1660e01b81526004016113aa9190613f97565b60206040518083038186803b1580156113c257600080fd5b505afa1580156113d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113fa9190810190613636565b156114175760405162461bcd60e51b8152600401610793906140f8565b600b548510156114395760405162461bcd60e51b815260040161079390614148565b6006546040516302d35b2d60e61b815260009182916001600160a01b039091169063b4d6cb40906114709089908990600401613fb3565b604080518083038186803b15801561148757600080fd5b505afa15801561149b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114bf9190810190613654565b915091508180156114ce575080155b6114ea5760405162461bcd60e51b8152600401610793906140d8565b6114f48786610ee9565b8611156115135760405162461bcd60e51b815260040161079390614138565b600061152a600c548861283c90919063ffffffff16565b9050600061153e888363ffffffff611e6e16565b9050600660009054906101000a90046001600160a01b03166001600160a01b031663b3b467326040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561159057600080fd5b505af11580156115a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115c891908101906136a2565b60408051610120810182528281523360208083019182528284018e8152606084018d8152608085018f81528d151560a08701908152600060c0880181815260e08901828152426101008b019081528c84526005988990529a9092209851895596516001890180546001600160a01b0319166001600160a01b03909216919091179055935160028801559151600387015551600486015551918401805460ff191692151592909217909155905160068301555160078201559051600882015590955061169290612851565b61169c8288612943565b851561188f576116aa612b2f565b6001600160a01b031663867904b4336116c1612821565b6001600160a01b031663654a60ac8b86631cd554d160e21b6040518463ffffffff1660e01b81526004016116f793929190613fe1565b60206040518083038186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061174791908101906136a2565b6040518363ffffffff1660e01b8152600401611764929190613f34565b600060405180830381600087803b15801561177e57600080fd5b505af1158015611792573d6000803e3d6000fd5b505060065460405163e31f27c160e01b81526001600160a01b03909116925063e31f27c191506117c8908a908c90600401613fb3565b600060405180830381600087803b1580156117e257600080fd5b505af11580156117f6573d6000803e3d6000fd5b5050506000888152600960205260409020546001600160a01b031615905061188a576000878152600960205260409081902054905163db454a5160e01b81526001600160a01b039091169063db454a51906118579033908c90600401613f34565b600060405180830381600087803b15801561187157600080fd5b505af1158015611885573d6000803e3d6000fd5b505050505b61196b565b6000878152600860205260409020546118a790612b46565b6001600160a01b031663867904b433836040518363ffffffff1660e01b81526004016118d4929190613f34565b600060405180830381600087803b1580156118ee57600080fd5b505af1158015611902573d6000803e3d6000fd5b50506006546040516375ca5def60e11b81526001600160a01b03909116925063eb94bbde9150611938908a908c90600401613fb3565b600060405180830381600087803b15801561195257600080fd5b505af1158015611966573d6000803e3d6000fd5b505050505b336001600160a01b03167f604952b18be5fed608cbdd28101dc57bd667055c9678ec6d44fb1d8e4c7c172a868a8c8b876040516119ac9594939291906142f5565b60405180910390a250505050949350505050565b60006119ca61272b565b6119d26127cd565b600082116119f25760405162461bcd60e51b815260040161079390614178565b60006119fe8486612b51565b9050611a0f33826003015485612ba5565b600a54611a1a611e96565b6001600160a01b031663e99f9647836004546040518363ffffffff1660e01b8152600401611a499291906141d0565b60206040518083038186803b158015611a6157600080fd5b505afa158015611a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a9991908101906136a2565b10611ab65760405162461bcd60e51b815260040161079390614158565b6000611ac0611e96565b6001600160a01b031663fbfeca4083600a546004546040518463ffffffff1660e01b8152600401611af3939291906141df565b60206040518083038186803b158015611b0b57600080fd5b505afa158015611b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b4391908101906136a2565b90506000848210611b545784611b56565b815b90506000611b7584600601548560040154611d2790919063ffffffff16565b9050808210611b9657611b89883386612c5d565b9550610678945050505050565b611ba533856003015484612ba5565b611baf8483612cce565b611bb7611e96565b6001600160a01b0316633c4aa0f38560030154846004546040518463ffffffff1660e01b8152600401611bec93929190613fe1565b60206040518083038186803b158015611c0457600080fd5b505afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c3c91908101906136a2565b6002850154909550611c54908663ffffffff611e6e16565b60028501556003840154600090815260086020526040902054611c7690612b46565b6001600160a01b0316639dc29fac33846040518363ffffffff1660e01b8152600401611ca3929190613f34565b600060405180830381600087803b158015611cbd57600080fd5b505af1158015611cd1573d6000803e3d6000fd5b50505050876001600160a01b03167fb6e43890aeea54fbe6c0ed628e78172a0ff30bbcb1d70d8b130b12c366bac4c588338589604051611d149493929190614274565b60405180910390a2505050509392505050565b6000828201838110156106785760405162461bcd60e51b815260040161079390614078565b600080611d5761272b565b611d5f6127cd565b6000611d6b8486612b51565b60408051610120810182528254815260018301546001600160a01b031660208201526002830154918101919091526003820154606082015260048201546080820152600582015460ff16151560a0820152600682015460c0820152600782015460e08201526008820154610100820152909150611de790612ebd565b611df2858683612f0a565b60405191945092506001600160a01b038616907fcab22a4e95d29d40da2ace3f6ec72b49954a9bc7b2584f8fd47bf7f357a3ed6f90611e32908790613f97565b60405180910390a2509250929050565b6000546001600160a01b03163314611e6c5760405162461bcd60e51b8152600401610793906140b8565b565b600082821115611e905760405162461bcd60e51b815260040161079390614098565b50900390565b6000611eb26d10dbdb1b185d195c985b155d1a5b60921b613170565b905090565b600080611ec261272b565b611eca6127cd565b6000611ed68533612b51565b6002810154909150611eee908563ffffffff611e6e16565b6002820155611efc816131cd565b336001600160a01b03167ffae26280bca25d80f1501a9e363c73d3845e651c9aaae54f1fc09a9dcd5f330386868460020154604051611f3d93929190613fe1565b60405180910390a28060040154816002015492509250505b9250929050565b600080611f6761272b565b611f6f6127cd565b60008311611f8f5760405162461bcd60e51b815260040161079390614128565b60008481526005602052604090206007810154611fab90613206565b611fb481612851565b6002810154611fc9908563ffffffff611d2716565b600282018190556040516001600160a01b038816917f0b1992dffc262be88559dcaf96464e9d661d8bfca7e82f2bb73e31932a82187c9161200e918991899190613fe1565b60405180910390a2806004015481600201549250925050935093915050565b604080516001808252818301909252606091602080830190803883390190505090506e466c657869626c6553746f7261676560881b8160008151811061206f57fe5b60200260200101818152505090565b606081518351016040519080825280602002602001820160405280156120ae578160200160208202803883390190505b50905060005b83518110156120f0578381815181106120c957fe5b60200260200101518282815181106120dd57fe5b60209081029190910101526001016120b4565b5060005b82518110156121335782818151811061210957fe5b602002602001015182828651018151811061212057fe5b60209081029190910101526001016120f4565b5092915050565b60008061214561272b565b61214d6127cd565b6000848152600560208181526040928390208351610120810185528154815260018201546001600160a01b03169281019290925260028101549382019390935260038301546060820152600483015460808201529082015460ff16151560a0820152600682015460c0820152600782015460e082015260088201546101008201526121d790612ebd565b6121e686826003015486612ba5565b6121ef81612851565b6121f98185612cce565b600381015460009081526008602052604090205461221690612b46565b6001600160a01b0316639dc29fac87866040518363ffffffff1660e01b8152600401612243929190613f6a565b600060405180830381600087803b15801561225d57600080fd5b505af1158015612271573d6000803e3d6000fd5b50505050428160080181905550856001600160a01b0316876001600160a01b03167fdf10512219e869922340b1b24b21d7d79bf71f411a6391cc7c3ef5dd2fe89e7f878785600401546040516122c993929190613fe1565b60405180910390a380600401548160020154925092505094509492505050565b6000806122f461272b565b6122fc6127cd565b60006123088533612b51565b60408051610120810182528254815260018301546001600160a01b031660208201526002830154918101919091526003820154606082015260048201546080820152600582015460ff16151560a0820152600682015460c0820152600782015460e0820152600882015461010082015290915061238490612ebd565b6004810154612399908563ffffffff611d2716565b60048201556123a7816131cd565b60006123be600c548661283c90919063ffffffff16565b905060006123d2868363ffffffff611e6e16565b600584015490915060ff16156125df57600654600384015460405163e31f27c160e01b81526001600160a01b039092169163e31f27c191612417918a90600401613fb3565b600060405180830381600087803b15801561243157600080fd5b505af1158015612445573d6000803e3d6000fd5b50505050612451612b2f565b6001600160a01b031663867904b433612468612821565b6001600160a01b031663654a60ac876003015486631cd554d160e21b6040518463ffffffff1660e01b81526004016124a293929190613fe1565b60206040518083038186803b1580156124ba57600080fd5b505afa1580156124ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124f291908101906136a2565b6040518363ffffffff1660e01b815260040161250f929190613f34565b600060405180830381600087803b15801561252957600080fd5b505af115801561253d573d6000803e3d6000fd5b5050505060038301546000908152600960205260409020546001600160a01b0316156125da5760038301546000908152600960205260409081902054905163db454a5160e01b81526001600160a01b039091169063db454a51906125a79033908a90600401613f34565b600060405180830381600087803b1580156125c157600080fd5b505af11580156125d5573d6000803e3d6000fd5b505050505b6126c3565b60065460038401546040516375ca5def60e11b81526001600160a01b039092169163eb94bbde91612614918a90600401613fb3565b600060405180830381600087803b15801561262e57600080fd5b505af1158015612642573d6000803e3d6000fd5b50505060038401546000908152600860205260409020546126639150612b46565b6001600160a01b031663867904b433836040518363ffffffff1660e01b8152600401612690929190613f34565b600060405180830381600087803b1580156126aa57600080fd5b505af11580156126be573d6000803e3d6000fd5b505050505b6126d1828460030154612943565b42600884015560405133907f5754fe57f36ac0f121901d7555aba517e6608590429d86a81c662cf3583106549061270b908a908a90613fb3565b60405180910390a282600401548360020154945094505050509250929050565b612733612821565b6001600160a01b0316632528f0fe6004546040518263ffffffff1660e01b81526004016127609190613f97565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127b09190810190613636565b15611e6c5760405162461bcd60e51b8152600401610793906140f8565b6127d5613223565b6001600160a01b0316637c3125416040518163ffffffff1660e01b815260040160006040518083038186803b15801561280d57600080fd5b505afa158015610835573d6000803e3d6000fd5b6000611eb26c45786368616e6765526174657360981b613170565b60006106788383670de0b6b3a764000061323d565b600654600782015460038301546005840154604051634002a33360e11b815260009485946001600160a01b03909116936380054666936128999360ff909116906004016142b2565b6040805180830381600087803b1580156128b257600080fd5b505af11580156128c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128ea91908101906136df565b9150915060008360070154600014612916576004840154612911908463ffffffff61327916565b612919565b60005b6006850154909150612931908263ffffffff611d2716565b60068501555060079092019190915550565b8115610a4857631cd554d160e21b81146129e85761295f612821565b6001600160a01b031663654a60ac8284631cd554d160e21b6040518463ffffffff1660e01b815260040161299593929190613fe1565b60206040518083038186803b1580156129ad57600080fd5b505afa1580156129c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129e591908101906136a2565b91505b6129f0612b2f565b6001600160a01b031663867904b4612a066132a3565b6001600160a01b031663eb1edd616040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3e57600080fd5b505afa158015612a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a769190810190613503565b846040518363ffffffff1660e01b8152600401612a94929190613f6a565b600060405180830381600087803b158015612aae57600080fd5b505af1158015612ac2573d6000803e3d6000fd5b50505050612ace6132a3565b6001600160a01b03166322bf55ef836040518263ffffffff1660e01b8152600401612af99190613f97565b600060405180830381600087803b158015612b1357600080fd5b505af1158015612b27573d6000803e3d6000fd5b505050505050565b6000611eb26814de5b9d1a1cd554d160ba1b613170565b6000610f2882613170565b60008281526005602052604090206007810154612b6d90613206565b60018101546001600160a01b03838116911614612b9c5760405162461bcd60e51b815260040161079390614108565b610f2881612851565b6000828152600860205260409020548190612bbf90612b46565b6001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401612bea9190613f26565b60206040518083038186803b158015612c0257600080fd5b505afa158015612c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c3a91908101906136a2565b1015612c585760405162461bcd60e51b8152600401610793906140a8565b505050565b600080612c6b858585612f0a565b8092508193505050836001600160a01b0316856001600160a01b03167f697721ed1b9d4866cb1aaa0692f62bb3abc1b01c2dafeaad053ffd4532aa7dbb85600001548585604051612cbe93929190613fe1565b60405180910390a3935093915050565b60008111612cee5760405162461bcd60e51b815260040161079390614178565b600682015415612d5057600082600601548211612d0b5781612d11565b82600601545b6006840154909150612d29908263ffffffff611e6e16565b6006840155612d3e828263ffffffff611e6e16565b9150612d4e818460030154612943565b505b8015610a48576004820154612d6b908263ffffffff611e6e16565b6004830155600582015460ff1615612e88576006546003830154604051635246f2b960e01b81526001600160a01b0390921691635246f2b991612db2918590600401613fb3565b600060405180830381600087803b158015612dcc57600080fd5b505af1158015612de0573d6000803e3d6000fd5b5050505060038201546000908152600960205260409020546001600160a01b031615612e8357600382015460009081526009602052604090819020546001840154915163f3fef3a360e01b81526001600160a01b039182169263f3fef3a392612e50929116908590600401613f34565b600060405180830381600087803b158015612e6a57600080fd5b505af1158015612e7e573d6000803e3d6000fd5b505050505b610a48565b600654600383015460405163e50a31b360e01b81526001600160a01b039092169163e50a31b391612af9918590600401613fb3565b612eca8160e00151613206565b42612ee9612ed7306132b8565b6101008401519063ffffffff611d2716565b1115612f075760405162461bcd60e51b8152600401610793906140e8565b50565b6000806000612f2a84600601548560040154611d2790919063ffffffff16565b90508360040154925083600201549150612f4985856003015483612ba5565b6003840154600090815260086020526040902054612f6690612b46565b6001600160a01b0316639dc29fac86836040518363ffffffff1660e01b8152600401612f93929190613f6a565b600060405180830381600087803b158015612fad57600080fd5b505af1158015612fc1573d6000803e3d6000fd5b50505050600584015460ff16156130df576006546003850154600480870154604051635246f2b960e01b81526001600160a01b0390941693635246f2b99361300c9390929101613fb3565b600060405180830381600087803b15801561302657600080fd5b505af115801561303a573d6000803e3d6000fd5b5050505060038401546000908152600960205260409020546001600160a01b0316156130da5760038401546000908152600960205260409081902054600480870154925163f3fef3a360e01b81526001600160a01b039092169263f3fef3a3926130a7928b929101613f6a565b600060405180830381600087803b1580156130c157600080fd5b505af11580156130d5573d6000803e3d6000fd5b505050505b61314c565b600654600385015460048087015460405163e50a31b360e01b81526001600160a01b039094169363e50a31b3936131199390929101613fb3565b600060405180830381600087803b15801561313357600080fd5b505af1158015613147573d6000803e3d6000fd5b505050505b61315e84600601548560030154612943565b6131678461338b565b50935093915050565b60008181526003602090815260408083205490516001600160a01b0390911691821515916131a091869101613ef0565b604051602081830303815290604052906121335760405162461bcd60e51b81526004016107939190614017565b60048101546131db57612f07565b600a5481546131e9906111b4565b11612f075760405162461bcd60e51b815260040161079390614028565b80612f075760405162461bcd60e51b815260040161079390614088565b6000611eb26b53797374656d53746174757360a01b613170565b600080600a8304613254868663ffffffff6133b016565b8161325b57fe5b0490506005600a82061061326d57600a015b600a9004949350505050565b6000670de0b6b3a7640000613294848463ffffffff6133b016565b8161329b57fe5b049392505050565b6000611eb266119959541bdbdb60ca1b613170565b60006132c26133ea565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b6f696e746572616374696f6e44656c617960801b85604051602001613308929190613eca565b604051602081830303815290604052805190602001206040518363ffffffff1660e01b815260040161333b929190613fb3565b60206040518083038186803b15801561335357600080fd5b505afa158015613367573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f2891908101906136a2565b6000600482018190556002820181905560068201819055600782015542600890910155565b6000826133bf57506000610f28565b828202828482816133cc57fe5b04146106785760405162461bcd60e51b8152600401610793906140c8565b6000611eb26e466c657869626c6553746f7261676560881b613170565b6040518061012001604052806000815260200160006001600160a01b031681526020016000815260200160008019168152602001600081526020016000151581526020016000815260200160008152602001600081525090565b8035610f288161440e565b8051610f288161440e565b60008083601f84011261348957600080fd5b50813567ffffffffffffffff8111156134a157600080fd5b602083019150836020820283011115611f5557600080fd5b8035610f2881614422565b8051610f2881614422565b8035610f288161442b565b8051610f288161442b565b6000602082840312156134f757600080fd5b6000610cf38484613461565b60006020828403121561351557600080fd5b6000610cf3848461346c565b6000806040838503121561353457600080fd5b60006135408585613461565b9250506020613551858286016134cf565b9150509250929050565b60008060006060848603121561357057600080fd5b600061357c8686613461565b935050602061358d868287016134cf565b925050604061359e868287016134cf565b9150509250925092565b600080600080604085870312156135be57600080fd5b843567ffffffffffffffff8111156135d557600080fd5b6135e187828801613477565b9450945050602085013567ffffffffffffffff81111561360057600080fd5b61360c87828801613477565b95989497509550505050565b60006020828403121561362a57600080fd5b6000610cf384846134b9565b60006020828403121561364857600080fd5b6000610cf384846134c4565b6000806040838503121561366757600080fd5b600061367385856134c4565b9250506020613551858286016134c4565b60006020828403121561369657600080fd5b6000610cf384846134cf565b6000602082840312156136b457600080fd5b6000610cf384846134da565b600080604083850312156136d357600080fd5b600061354085856134cf565b600080604083850312156136f257600080fd5b60006136fe85856134da565b9250506020613551858286016134da565b600061371b83836137ae565b505060200190565b61372c8161437b565b82525050565b61372c8161436b565b61372c6137478261436b565b6143ed565b600061375782614347565b613761818561434b565b935061376c83614341565b8060005b8381101561379a578151613784888261370f565b975061378f83614341565b925050600101613770565b509495945050505050565b61372c81614376565b61372c81610950565b61372c6137c382610950565b610950565b61372c81614382565b60006137dc82614347565b6137e6818561434b565b93506137f681856020860161438d565b6137ff816143fe565b9093019392505050565b6000613816600e8361434b565b6d43726174696f20746f6f206c6f7760901b815260200192915050565b600061384060358361434b565b7f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7581527402063616e20616363657074206f776e65727368697605c1b602082015260400192915050565b600061389760158361434b565b74082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b815260200192915050565b60006138c8600f8361434b565b6e151c985b9cd9995c8819985a5b1959608a1b815260200192915050565b60006138f360148361434b565b734e6f7420616c6c6f77656420746f20697373756560601b815260200192915050565b6000613923601b8361434b565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b600061395c600e8361434b565b6d131bd85b881a5cc818db1bdcd95960921b815260200192915050565b6000613986601e8361434b565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b60006139bf601183614354565b70026b4b9b9b4b7339030b2323932b9b99d1607d1b815260110192915050565b60006139ec60128361434b565b714e6f7420656e6f7567682062616c616e636560701b815260200192915050565b6000613a1a602f8361434b565b7f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726681526e37b936903a3434b99030b1ba34b7b760891b602082015260400192915050565b6000613a6b60218361434b565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613aae601a8361434b565b7f44656274206c696d6974206f7220696e76616c69642072617465000000000000815260200192915050565b6000613ae760138361434b565b72149958d95b9d1b1e481a5b9d195c9858dd1959606a1b815260200192915050565b6000613b16601983614354565b7f5265736f6c766572206d697373696e67207461726765743a2000000000000000815260190192915050565b6000613b4f600c8361434b565b6b496e76616c6964207261746560a01b815260200192915050565b6000613b7760108361434b565b6f26bab9ba103132903137b93937bbb2b960811b815260200192915050565b6000610f28600083614354565b6000613bb0600d8361434b565b6c13dc195b88191a5cd8589b1959609a1b815260200192915050565b6000613bd960178361434b565b7f4465706f736974206d7573742062652061626f76652030000000000000000000815260200192915050565b6000613c1260178361434b565b7f457863656564206d617820626f72726f7720706f776572000000000000000000815260200192915050565b6000613c4b60158361434b565b74139bdd08195b9bdd59da0818dbdb1b185d195c985b605a1b815260200192915050565b6000613c7c60168361434b565b7543726174696f2061626f7665206c697120726174696f60501b815260200192915050565b6000613cae601f8361434b565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000613ce760178361434b565b7f5061796d656e74206d7573742062652061626f76652030000000000000000000815260200192915050565b8051610120830190613d2584826137ae565b506020820151613d386020850182613732565b506040820151613d4b60408501826137ae565b506060820151613d5e60608501826137ae565b506080820151613d7160808501826137ae565b5060a0820151613d8460a08501826137a5565b5060c0820151613d9760c08501826137ae565b5060e0820151613daa60e08501826137ae565b506101008201516108356101008501826137ae565b8054610120830190613dd0816143df565b613dda85826137ae565b50506001820154613dea816143b9565b613df76020860182613732565b50506002820154613e07816143df565b613e1460408601826137ae565b50506003820154613e24816143df565b613e3160608601826137ae565b50506004820154613e41816143df565b613e4e60808601826137ae565b50506005820154613e5e816143cc565b613e6b60a08601826137a5565b50506006820154613e7b816143df565b613e8860c08601826137ae565b50506007820154613e98816143df565b613ea560e08601826137ae565b50506008820154613eb5816143df565b613ec36101008601826137ae565b5050505050565b6000613ed682856137b7565b602082019150613ee6828461373b565b5060140192915050565b6000613efb826139b2565b9150613f0782846137b7565b50602001919050565b6000613efb82613b09565b6000610f2882613b96565b60208101610f288284613732565b60408101613f428285613723565b61067860208301846137ae565b60408101613f5d8285613732565b6106786020830184613732565b60408101613f428285613732565b60208082528101610678818461374c565b60208101610f2882846137a5565b60208101610f2882846137ae565b60408101613f5d82856137ae565b60408101613f4282856137ae565b60408101613fcf82856137ae565b8181036020830152610cf381846137d1565b60608101613fef82866137ae565b613ffc60208301856137ae565b610cf360408301846137ae565b60208101610f2882846137c8565b6020808252810161067881846137d1565b60208082528101610f2881613809565b60208082528101610f2881613833565b60208082528101610f288161388a565b60208082528101610f28816138bb565b60208082528101610f28816138e6565b60208082528101610f2881613916565b60208082528101610f288161394f565b60208082528101610f2881613979565b60208082528101610f28816139df565b60208082528101610f2881613a0d565b60208082528101610f2881613a5e565b60208082528101610f2881613aa1565b60208082528101610f2881613ada565b60208082528101610f2881613b42565b60208082528101610f2881613b6a565b60208082528101610f2881613ba3565b60208082528101610f2881613bcc565b60208082528101610f2881613c05565b60208082528101610f2881613c3e565b60208082528101610f2881613c6f565b60208082528101610f2881613ca1565b60208082528101610f2881613cda565b61014081016141978285613d13565b6106786101208301846137ae565b61016081016141b48286613d13565b6141c26101208301856137ae565b610cf36101408301846137ae565b61014081016141978285613dbf565b61016081016141b48286613dbf565b61012081016141fd828c6137ae565b61420a602083018b613732565b614217604083018a6137ae565b61422460608301896137ae565b61423160808301886137ae565b61423e60a08301876137a5565b61424b60c08301866137ae565b61425860e08301856137ae565b6142666101008301846137ae565b9a9950505050505050505050565b6080810161428282876137ae565b61428f6020830186613723565b61429c60408301856137ae565b6142a960608301846137ae565b95945050505050565b606081016142c082866137ae565b6142cd60208301856137ae565b610cf360408301846137a5565b608081016142e882876137ae565b61428f60208301866137ae565b60a0810161430382886137ae565b61431060208301876137ae565b61431d60408301866137ae565b61432a60608301856137ae565b61433760808301846137ae565b9695505050505050565b60200190565b5190565b90815260200190565b919050565b6001600160a01b031690565b60ff1690565b6000610f2882614359565b151590565b6000610f28825b6000610f288261436b565b60005b838110156143a8578181015183820152602001614390565b838111156108355750506000910152565b6000610f286143c783610950565b614359565b6000610f286143da83610950565b614365565b6000610f286137c383610950565b6000610f28826000610f2882614408565b601f01601f191690565b60601b90565b6144178161436b565b8114612f0757600080fd5b61441781614376565b6144178161095056fea365627a7a723158207ea733850eab679e1a0115a60d2318d891ec530c9063b5a96fa092a6360815b46c6578706572696d656e74616cf564736f6c63430005100040", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "contract ICollateralManager", + "name": "_manager", + "type": "address" + }, + { + "internalType": "address", + "name": "_resolver", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_collateralKey", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_minCratio", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minCollateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "name", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "destination", + "type": "address" + } + ], + "name": "CacheUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "canOpenLoans", + "type": "bool" + } + ], + "name": "CanOpenLoansUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountDeposited", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralAfter", + "type": "uint256" + } + ], + "name": "CollateralDeposited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountWithdrawn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralAfter", + "type": "uint256" + } + ], + "name": "CollateralWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "issueFeeRate", + "type": "uint256" + } + ], + "name": "IssueFeeRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "LoanClosed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountLiquidated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralLiquidated", + "type": "uint256" + } + ], + "name": "LoanClosedByLiquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountRepaid", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralAfter", + "type": "uint256" + } + ], + "name": "LoanClosedByRepayment", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "issuanceFee", + "type": "uint256" + } + ], + "name": "LoanCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "LoanDrawnDown", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountLiquidated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralLiquidated", + "type": "uint256" + } + ], + "name": "LoanPartiallyLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "repayer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountRepaid", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountAfter", + "type": "uint256" + } + ], + "name": "LoanRepaymentMade", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "minCollateral", + "type": "uint256" + } + ], + "name": "MinCollateralUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnerNominated", + "type": "event" + }, + { + "constant": false, + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "rewardsContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "synth", + "type": "bytes32" + } + ], + "name": "addRewardsContracts", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32[]", + "name": "_synthNamesInResolver", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_synthKeys", + "type": "bytes32[]" + } + ], + "name": "addSynths", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32[]", + "name": "_synthNamesInResolver", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_synthKeys", + "type": "bytes32[]" + } + ], + "name": "areSynthsAndCurrenciesSet", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "canOpenLoans", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "claim", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "close", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "collateralKey", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "collateralRatio", + "outputs": [ + { + "internalType": "uint256", + "name": "cratio", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "draw", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isResolverCached", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "issueFeeRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "liquidate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "liquidationAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "liqAmount", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "loans", + "outputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "short", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "accruedInterest", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "interestIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastInteraction", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "contract ICollateralManager", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + } + ], + "name": "maxLoan", + "outputs": [ + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minCollateral", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minCratio", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "nominateNewOwner", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nominatedOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "currency", + "type": "bytes32" + } + ], + "name": "open", + "outputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "pendingWithdrawals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "rebuildCache", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "repay", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "resolver", + "outputs": [ + { + "internalType": "contract AddressResolver", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "resolverAddressesRequired", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "addresses", + "type": "bytes32[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bool", + "name": "_canOpenLoans", + "type": "bool" + } + ], + "name": "setCanOpenLoans", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_issueFeeRate", + "type": "uint256" + } + ], + "name": "setIssueFeeRate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_minCollateral", + "type": "uint256" + } + ], + "name": "setMinCollateral", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "shortingRewards", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "synths", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "synthsByKey", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "principal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateral", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "source": { + "keccak256": "0xd83c3667bcacd4d33cf0fc649cee03d85e7d3914abb7ce6c9898e6ee1d66da81", + "urls": [ + "bzz-raw://77bd631dcee01051f611ea2927feb37c87f5532ce90537b2dc9b8952b85c3576", + "dweb:/ipfs/QmWHiciYDoG7sNnyA7kUzeSmQy4EVV8ktrDNVHDuQhq7tx" + ] + }, + "metadata": { + "compiler": { + "version": "0.5.16+commit.9c3226ce" + }, + "language": "Solidity", + "settings": { + "compilationTarget": { + "CollateralEth.sol": "CollateralEth" + }, + "evmVersion": "istanbul", + "libraries": {}, + "optimizer": { + "enabled": true, + "runs": 200 + }, + "remappings": [] + }, + "sources": { + "CollateralEth.sol": { + "keccak256": "0xd83c3667bcacd4d33cf0fc649cee03d85e7d3914abb7ce6c9898e6ee1d66da81", + "urls": [ + "bzz-raw://77bd631dcee01051f611ea2927feb37c87f5532ce90537b2dc9b8952b85c3576", + "dweb:/ipfs/QmWHiciYDoG7sNnyA7kUzeSmQy4EVV8ktrDNVHDuQhq7tx" + ] + } + }, + "version": 1 + } } } } diff --git a/publish/deployed/mainnet-ovm/params.json b/publish/deployed/mainnet-ovm/params.json index a7bb2d1ae4..ee856ec252 100644 --- a/publish/deployed/mainnet-ovm/params.json +++ b/publish/deployed/mainnet-ovm/params.json @@ -18,7 +18,7 @@ "SHORTS": ["sBTC", "sETH", "sLINK"], "MAX_DEBT": "75000000000000000000000000", "MAX_SKEW_RATE": "200000000000000000", - "BASE_BORROW_RATE": "158443823", + "BASE_BORROW_RATE": "950662938", "BASE_SHORT_RATE": "158443823" } }, @@ -32,5 +32,14 @@ "INTERACTION_DELAY": "0", "COLLAPSE_FEE_RATE": "0" } + }, + { + "name": "COLLATERAL_ETH", + "value": { + "SYNTHS": ["sUSD"], + "MIN_CRATIO": "1200000000000000000", + "MIN_COLLATERAL": "100000000000000000", + "ISSUE_FEE_RATE": "0" + } } ] diff --git a/publish/deployed/mainnet-ovm/versions.json b/publish/deployed/mainnet-ovm/versions.json index 6f06739da9..b1a2558460 100644 --- a/publish/deployed/mainnet-ovm/versions.json +++ b/publish/deployed/mainnet-ovm/versions.json @@ -393,8 +393,9 @@ }, "Synthetix": { "address": "0xff4287311138ad3BD051F84524B2eA3A682944a5", - "status": "current", - "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749" + "status": "replaced", + "keccak256": "0xbbe79669c2586e5f0a7f35a0577d21b881e0e083b9fc297fa16d6c1de064c749", + "replaced_in": "v2.56.1" }, "DebtCache": { "address": "0xe1f47188168837485527A5B44E7FA7ca55F29C65", @@ -589,5 +590,25 @@ "keccak256": "0x582cac91f50cfefc154d67097081d0dd0d4877333df51c3cfe19485f80ef7e74" } } + }, + "v2.56.1": { + "tag": "v2.56.1", + "fulltag": "v2.56.1", + "release": "Alhena", + "network": "mainnet", + "date": "2021-12-15T18:16:59-05:00", + "commit": "324105690195d2c0925ffbfffe5d0bba8e98fad7", + "contracts": { + "Synthetix": { + "address": "0x20eBfbdD14c9D8093E9AC33e736Ac61bbaC90092", + "status": "current", + "keccak256": "0x87c92d55af4f4b01932ec25770439770836ed60b9652a3f4ab1ec6e0d82d302a" + }, + "CollateralEth": { + "address": "0x308AD16ef90fe7caCb85B784A603CB6E71b1A41a", + "status": "current", + "keccak256": "0xd83c3667bcacd4d33cf0fc649cee03d85e7d3914abb7ce6c9898e6ee1d66da81" + } + } } } diff --git a/publish/deployed/mainnet/config.json b/publish/deployed/mainnet/config.json index 1e92b0c606..d2ea2979fb 100644 --- a/publish/deployed/mainnet/config.json +++ b/publish/deployed/mainnet/config.json @@ -319,5 +319,14 @@ }, "OwnerRelayOnEthereum": { "deploy": false + }, + "TokenStatesETHBTC": { + "deploy": false + }, + "ProxysETHBTC": { + "deploy": false + }, + "SynthsETHBTC": { + "deploy": false } } diff --git a/publish/deployed/mainnet/deployment.json b/publish/deployed/mainnet/deployment.json index d7f42cf641..2faa3ddc2f 100644 --- a/publish/deployed/mainnet/deployment.json +++ b/publish/deployed/mainnet/deployment.json @@ -989,6 +989,33 @@ "timestamp": "2021-11-23T22:26:10.000Z", "txn": "https://etherscan.io/tx/0xcb2daf5c04fde995ba13c6ca4e3eb9edd794f3031f0380ce653abed742ae4834", "network": "mainnet" + }, + "TokenStatesETHBTC": { + "name": "TokenStatesETHBTC", + "address": "0x042A7A0022A7695454ac5Be77a4860e50c9683fC", + "source": "TokenState", + "link": "https://etherscan.io/address/0x042A7A0022A7695454ac5Be77a4860e50c9683fC", + "timestamp": "2021-12-15T22:05:17.310Z", + "txn": "", + "network": "mainnet" + }, + "ProxysETHBTC": { + "name": "ProxysETHBTC", + "address": "0x104eDF1da359506548BFc7c25bA1E28C16a70235", + "source": "ProxyERC20", + "link": "https://etherscan.io/address/0x104eDF1da359506548BFc7c25bA1E28C16a70235", + "timestamp": "2021-12-15T22:05:20.000Z", + "txn": "https://etherscan.io/tx/0xef2ff387f4ccca14ff4b02d9226420cdd4766873d99f8733a92ec78e8fea2dae", + "network": "mainnet" + }, + "SynthsETHBTC": { + "name": "SynthsETHBTC", + "address": "0xcc3aab773e2171b2E257Ee17001400eE378aa52B", + "source": "MultiCollateralSynth", + "link": "https://etherscan.io/address/0xcc3aab773e2171b2E257Ee17001400eE378aa52B", + "timestamp": "2021-12-15T22:13:15.518Z", + "txn": "", + "network": "mainnet" } }, "sources": { @@ -8146,8 +8173,7 @@ ], "payable": false, "stateMutability": "nonpayable", - "type": "constructor", - "signature": "constructor" + "type": "constructor" }, { "anonymous": false, @@ -8160,8 +8186,7 @@ } ], "name": "AssociatedContractUpdated", - "type": "event", - "signature": "0x73f20cff579e8a4086fa607db83867595f1b6a798e718c0bfa0b94a404128e03" + "type": "event" }, { "anonymous": false, @@ -8180,8 +8205,7 @@ } ], "name": "OwnerChanged", - "type": "event", - "signature": "0xb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c" + "type": "event" }, { "anonymous": false, @@ -8194,8 +8218,7 @@ } ], "name": "OwnerNominated", - "type": "event", - "signature": "0x906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22" + "type": "event" }, { "constant": false, @@ -8204,8 +8227,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x79ba5097" + "type": "function" }, { "constant": true, @@ -8231,8 +8253,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0xdd62ed3e" + "type": "function" }, { "constant": true, @@ -8247,8 +8268,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0xaefc4ccb" + "type": "function" }, { "constant": true, @@ -8269,8 +8289,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x70a08231" + "type": "function" }, { "constant": false, @@ -8285,8 +8304,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x1627540c" + "type": "function" }, { "constant": true, @@ -8301,8 +8319,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x53a47bb7" + "type": "function" }, { "constant": true, @@ -8317,8 +8334,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x8da5cb5b" + "type": "function" }, { "constant": false, @@ -8343,8 +8359,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0xda46098c" + "type": "function" }, { "constant": false, @@ -8359,8 +8374,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x52f445ca" + "type": "function" }, { "constant": false, @@ -8380,8 +8394,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0xb46310f6" + "type": "function" } ], "source": { @@ -16305,7 +16318,7 @@ } }, "ProxyERC20": { - "bytecode": "608060405234801561001057600080fd5b50604051610f7f380380610f7f8339818101604052602081101561003357600080fd5b505180806001600160a01b038116610092576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1505050610e83806100fc6000396000f3fe6080604052600436106100f35760003560e01c8063776d1a011161008a57806395d89b411161005957806395d89b4114610473578063a9059cbb14610488578063d4b83992146104c1578063dd62ed3e146104d6576100f3565b8063776d1a011461038157806379ba5097146103b45780638da5cb5b146103c9578063907dff97146103de576100f3565b806323b872dd116100c657806323b872dd146102af578063313ce567146102f257806353a47bb71461031d57806370a082311461034e576100f3565b806306fdde031461017c578063095ea7b3146102065780631627540c1461025357806318160ddd14610288575b60025460408051635e33fc1960e11b815233600482015290516001600160a01b039092169163bc67f8329160248082019260009290919082900301818387803b15801561013f57600080fd5b505af1158015610153573d6000803e3d6000fd5b5050505060405136600082376000803683346002545af13d6000833e80610178573d82fd5b3d82f35b34801561018857600080fd5b50610191610511565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101cb5781810151838201526020016101b3565b50505050905090810190601f1680156101f85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561021257600080fd5b5061023f6004803603604081101561022957600080fd5b506001600160a01b038135169060200135610648565b604080519115158252519081900360200190f35b34801561025f57600080fd5b506102866004803603602081101561027657600080fd5b50356001600160a01b0316610736565b005b34801561029457600080fd5b5061029d610792565b60408051918252519081900360200190f35b3480156102bb57600080fd5b5061023f600480360360608110156102d257600080fd5b506001600160a01b03813581169160208101359091169060400135610808565b3480156102fe57600080fd5b506103076108ff565b6040805160ff9092168252519081900360200190f35b34801561032957600080fd5b50610332610944565b604080516001600160a01b039092168252519081900360200190f35b34801561035a57600080fd5b5061029d6004803603602081101561037157600080fd5b50356001600160a01b0316610953565b34801561038d57600080fd5b50610286600480360360208110156103a457600080fd5b50356001600160a01b03166109d6565b3480156103c057600080fd5b50610286610a32565b3480156103d557600080fd5b50610332610aee565b3480156103ea57600080fd5b50610286600480360360c081101561040157600080fd5b81019060208101813564010000000081111561041c57600080fd5b82018360208201111561042e57600080fd5b8035906020019184600183028401116401000000008311171561045057600080fd5b919350915080359060208101359060408101359060608101359060800135610afd565b34801561047f57600080fd5b50610191610c06565b34801561049457600080fd5b5061023f600480360360408110156104ab57600080fd5b506001600160a01b038135169060200135610c4b565b3480156104cd57600080fd5b50610332610d04565b3480156104e257600080fd5b5061029d600480360360408110156104f957600080fd5b506001600160a01b0381358116916020013516610d13565b600254604080516306fdde0360e01b815290516060926001600160a01b0316916306fdde03916004808301926000929190829003018186803b15801561055657600080fd5b505afa15801561056a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561059357600080fd5b81019080805160405193929190846401000000008211156105b357600080fd5b9083019060208201858111156105c857600080fd5b82516401000000008111828201881017156105e257600080fd5b82525081516020918201929091019080838360005b8381101561060f5781810151838201526020016105f7565b50505050905090810190601f16801561063c5780820380516001836020036101000a031916815260200191505b50604052505050905090565b60025460408051635e33fc1960e11b815233600482015290516000926001600160a01b03169163bc67f832916024808301928692919082900301818387803b15801561069357600080fd5b505af11580156106a7573d6000803e3d6000fd5b50506002546040805163095ea7b360e01b81526001600160a01b03888116600483015260248201889052915191909216935063095ea7b3925060448083019260209291908290030181600087803b15801561070157600080fd5b505af1158015610715573d6000803e3d6000fd5b505050506040513d602081101561072b57600080fd5b506001949350505050565b61073e610d9f565b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b600254604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156107d757600080fd5b505afa1580156107eb573d6000803e3d6000fd5b505050506040513d602081101561080157600080fd5b5051905090565b60025460408051635e33fc1960e11b815233600482015290516000926001600160a01b03169163bc67f832916024808301928692919082900301818387803b15801561085357600080fd5b505af1158015610867573d6000803e3d6000fd5b5050600254604080516323b872dd60e01b81526001600160a01b03898116600483015288811660248301526044820188905291519190921693506323b872dd925060648083019260209291908290030181600087803b1580156108c957600080fd5b505af11580156108dd573d6000803e3d6000fd5b505050506040513d60208110156108f357600080fd5b50600195945050505050565b6002546040805163313ce56760e01b815290516000926001600160a01b03169163313ce567916004808301926020929190829003018186803b1580156107d757600080fd5b6001546001600160a01b031681565b600254604080516370a0823160e01b81526001600160a01b038481166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b1580156109a457600080fd5b505afa1580156109b8573d6000803e3d6000fd5b505050506040513d60208110156109ce57600080fd5b505192915050565b6109de610d9f565b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f814250a3b8c79fcbe2ead2c131c952a278491c8f4322a79fe84b5040a810373e9181900360200190a150565b6001546001600160a01b03163314610a7b5760405162461bcd60e51b8152600401808060200182810382526035815260200180610deb6035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b031681565b6002546001600160a01b03163314610b53576040805162461bcd60e51b8152602060048201526014602482015273135d5cdd081899481c1c9bde1e481d185c99d95d60621b604482015290519081900360640190fd5b604080516020601f89018190048102820181019092528781528791606091908a908490819084018382808284376000920191909152509293508992505081159050610bbd5760018114610bc85760028114610bd45760038114610be15760048114610bef57610bfa565b8260208301a0610bfa565b868360208401a1610bfa565b85878460208501a2610bfa565b8486888560208601a3610bfa565b838587898660208701a45b50505050505050505050565b600254604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b41916004808301926000929190829003018186803b15801561055657600080fd5b60025460408051635e33fc1960e11b815233600482015290516000926001600160a01b03169163bc67f832916024808301928692919082900301818387803b158015610c9657600080fd5b505af1158015610caa573d6000803e3d6000fd5b50506002546040805163a9059cbb60e01b81526001600160a01b03888116600483015260248201889052915191909216935063a9059cbb925060448083019260209291908290030181600087803b15801561070157600080fd5b6002546001600160a01b031681565b60025460408051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301529151600093929092169163dd62ed3e91604480820192602092909190829003018186803b158015610d6c57600080fd5b505afa158015610d80573d6000803e3d6000fd5b505050506040513d6020811015610d9657600080fd5b50519392505050565b6000546001600160a01b03163314610de85760405162461bcd60e51b815260040180806020018281038252602f815260200180610e20602f913960400191505060405180910390fd5b56fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e6572736869704f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6ea265627a7a72315820d9fe4f5dd8e7296e50ed921f77c64c5a5801472804aae64777e9f58ae10b8d0664736f6c63430005100032", + "bytecode": "608060405234801561001057600080fd5b50604051610f7f380380610f7f8339818101604052602081101561003357600080fd5b505180806001600160a01b038116610092576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1505050610e83806100fc6000396000f3fe6080604052600436106100f35760003560e01c8063776d1a011161008a57806395d89b411161005957806395d89b4114610473578063a9059cbb14610488578063d4b83992146104c1578063dd62ed3e146104d6576100f3565b8063776d1a011461038157806379ba5097146103b45780638da5cb5b146103c9578063907dff97146103de576100f3565b806323b872dd116100c657806323b872dd146102af578063313ce567146102f257806353a47bb71461031d57806370a082311461034e576100f3565b806306fdde031461017c578063095ea7b3146102065780631627540c1461025357806318160ddd14610288575b60025460408051635e33fc1960e11b815233600482015290516001600160a01b039092169163bc67f8329160248082019260009290919082900301818387803b15801561013f57600080fd5b505af1158015610153573d6000803e3d6000fd5b5050505060405136600082376000803683346002545af13d6000833e80610178573d82fd5b3d82f35b34801561018857600080fd5b50610191610511565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101cb5781810151838201526020016101b3565b50505050905090810190601f1680156101f85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561021257600080fd5b5061023f6004803603604081101561022957600080fd5b506001600160a01b038135169060200135610648565b604080519115158252519081900360200190f35b34801561025f57600080fd5b506102866004803603602081101561027657600080fd5b50356001600160a01b0316610736565b005b34801561029457600080fd5b5061029d610792565b60408051918252519081900360200190f35b3480156102bb57600080fd5b5061023f600480360360608110156102d257600080fd5b506001600160a01b03813581169160208101359091169060400135610808565b3480156102fe57600080fd5b506103076108ff565b6040805160ff9092168252519081900360200190f35b34801561032957600080fd5b50610332610944565b604080516001600160a01b039092168252519081900360200190f35b34801561035a57600080fd5b5061029d6004803603602081101561037157600080fd5b50356001600160a01b0316610953565b34801561038d57600080fd5b50610286600480360360208110156103a457600080fd5b50356001600160a01b03166109d6565b3480156103c057600080fd5b50610286610a32565b3480156103d557600080fd5b50610332610aee565b3480156103ea57600080fd5b50610286600480360360c081101561040157600080fd5b81019060208101813564010000000081111561041c57600080fd5b82018360208201111561042e57600080fd5b8035906020019184600183028401116401000000008311171561045057600080fd5b919350915080359060208101359060408101359060608101359060800135610afd565b34801561047f57600080fd5b50610191610c06565b34801561049457600080fd5b5061023f600480360360408110156104ab57600080fd5b506001600160a01b038135169060200135610c4b565b3480156104cd57600080fd5b50610332610d04565b3480156104e257600080fd5b5061029d600480360360408110156104f957600080fd5b506001600160a01b0381358116916020013516610d13565b600254604080516306fdde0360e01b815290516060926001600160a01b0316916306fdde03916004808301926000929190829003018186803b15801561055657600080fd5b505afa15801561056a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561059357600080fd5b81019080805160405193929190846401000000008211156105b357600080fd5b9083019060208201858111156105c857600080fd5b82516401000000008111828201881017156105e257600080fd5b82525081516020918201929091019080838360005b8381101561060f5781810151838201526020016105f7565b50505050905090810190601f16801561063c5780820380516001836020036101000a031916815260200191505b50604052505050905090565b60025460408051635e33fc1960e11b815233600482015290516000926001600160a01b03169163bc67f832916024808301928692919082900301818387803b15801561069357600080fd5b505af11580156106a7573d6000803e3d6000fd5b50506002546040805163095ea7b360e01b81526001600160a01b03888116600483015260248201889052915191909216935063095ea7b3925060448083019260209291908290030181600087803b15801561070157600080fd5b505af1158015610715573d6000803e3d6000fd5b505050506040513d602081101561072b57600080fd5b506001949350505050565b61073e610d9f565b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b600254604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156107d757600080fd5b505afa1580156107eb573d6000803e3d6000fd5b505050506040513d602081101561080157600080fd5b5051905090565b60025460408051635e33fc1960e11b815233600482015290516000926001600160a01b03169163bc67f832916024808301928692919082900301818387803b15801561085357600080fd5b505af1158015610867573d6000803e3d6000fd5b5050600254604080516323b872dd60e01b81526001600160a01b03898116600483015288811660248301526044820188905291519190921693506323b872dd925060648083019260209291908290030181600087803b1580156108c957600080fd5b505af11580156108dd573d6000803e3d6000fd5b505050506040513d60208110156108f357600080fd5b50600195945050505050565b6002546040805163313ce56760e01b815290516000926001600160a01b03169163313ce567916004808301926020929190829003018186803b1580156107d757600080fd5b6001546001600160a01b031681565b600254604080516370a0823160e01b81526001600160a01b038481166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b1580156109a457600080fd5b505afa1580156109b8573d6000803e3d6000fd5b505050506040513d60208110156109ce57600080fd5b505192915050565b6109de610d9f565b600280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f814250a3b8c79fcbe2ead2c131c952a278491c8f4322a79fe84b5040a810373e9181900360200190a150565b6001546001600160a01b03163314610a7b5760405162461bcd60e51b8152600401808060200182810382526035815260200180610deb6035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b031681565b6002546001600160a01b03163314610b53576040805162461bcd60e51b8152602060048201526014602482015273135d5cdd081899481c1c9bde1e481d185c99d95d60621b604482015290519081900360640190fd5b604080516020601f89018190048102820181019092528781528791606091908a908490819084018382808284376000920191909152509293508992505081159050610bbd5760018114610bc85760028114610bd45760038114610be15760048114610bef57610bfa565b8260208301a0610bfa565b868360208401a1610bfa565b85878460208501a2610bfa565b8486888560208601a3610bfa565b838587898660208701a45b50505050505050505050565b600254604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b41916004808301926000929190829003018186803b15801561055657600080fd5b60025460408051635e33fc1960e11b815233600482015290516000926001600160a01b03169163bc67f832916024808301928692919082900301818387803b158015610c9657600080fd5b505af1158015610caa573d6000803e3d6000fd5b50506002546040805163a9059cbb60e01b81526001600160a01b03888116600483015260248201889052915191909216935063a9059cbb925060448083019260209291908290030181600087803b15801561070157600080fd5b6002546001600160a01b031681565b60025460408051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301529151600093929092169163dd62ed3e91604480820192602092909190829003018186803b158015610d6c57600080fd5b505afa158015610d80573d6000803e3d6000fd5b505050506040513d6020811015610d9657600080fd5b50519392505050565b6000546001600160a01b03163314610de85760405162461bcd60e51b815260040180806020018281038252602f815260200180610e20602f913960400191505060405180910390fd5b56fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e6572736869704f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6ea265627a7a72315820bc16ca473a169ecfb5918c5dcce84659bb9529548bc8336990487ca08ab50b1a64736f6c63430005100032", "abi": [ { "inputs": [ @@ -16317,8 +16330,7 @@ ], "payable": false, "stateMutability": "nonpayable", - "type": "constructor", - "signature": "constructor" + "type": "constructor" }, { "anonymous": false, @@ -16343,8 +16355,7 @@ } ], "name": "Approval", - "type": "event", - "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + "type": "event" }, { "anonymous": false, @@ -16363,8 +16374,7 @@ } ], "name": "OwnerChanged", - "type": "event", - "signature": "0xb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c" + "type": "event" }, { "anonymous": false, @@ -16377,8 +16387,7 @@ } ], "name": "OwnerNominated", - "type": "event", - "signature": "0x906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22" + "type": "event" }, { "anonymous": false, @@ -16391,8 +16400,7 @@ } ], "name": "TargetUpdated", - "type": "event", - "signature": "0x814250a3b8c79fcbe2ead2c131c952a278491c8f4322a79fe84b5040a810373e" + "type": "event" }, { "anonymous": false, @@ -16417,8 +16425,7 @@ } ], "name": "Transfer", - "type": "event", - "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + "type": "event" }, { "payable": true, @@ -16463,8 +16470,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x907dff97" + "type": "function" }, { "constant": false, @@ -16473,8 +16479,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x79ba5097" + "type": "function" }, { "constant": true, @@ -16500,8 +16505,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0xdd62ed3e" + "type": "function" }, { "constant": false, @@ -16527,8 +16531,7 @@ ], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x095ea7b3" + "type": "function" }, { "constant": true, @@ -16549,8 +16552,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x70a08231" + "type": "function" }, { "constant": true, @@ -16565,8 +16567,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x313ce567" + "type": "function" }, { "constant": true, @@ -16581,8 +16582,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x06fdde03" + "type": "function" }, { "constant": false, @@ -16597,8 +16597,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x1627540c" + "type": "function" }, { "constant": true, @@ -16613,8 +16612,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x53a47bb7" + "type": "function" }, { "constant": true, @@ -16629,8 +16627,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x8da5cb5b" + "type": "function" }, { "constant": false, @@ -16645,8 +16642,7 @@ "outputs": [], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x776d1a01" + "type": "function" }, { "constant": true, @@ -16661,8 +16657,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x95d89b41" + "type": "function" }, { "constant": true, @@ -16677,8 +16672,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0xd4b83992" + "type": "function" }, { "constant": true, @@ -16693,8 +16687,7 @@ ], "payable": false, "stateMutability": "view", - "type": "function", - "signature": "0x18160ddd" + "type": "function" }, { "constant": false, @@ -16720,8 +16713,7 @@ ], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0xa9059cbb" + "type": "function" }, { "constant": false, @@ -16752,15 +16744,14 @@ ], "payable": false, "stateMutability": "nonpayable", - "type": "function", - "signature": "0x23b872dd" + "type": "function" } ], "source": { - "keccak256": "0xfb133acce922041ba6b061ee7a8ce32c7908b0cbb37f343dd9fd81d532999bd8", + "keccak256": "0xa4731706c3292ed368ded616be2fcf28877d8a853cbce27be7d78e6a57636e9f", "urls": [ - "bzz-raw://9ea8edaed10b21ff232e019b44be802821ef5c62b47888b81d19c7232280ccc8", - "dweb:/ipfs/QmNvmS5845T4XjAsUms9WLHDjGxDRRuHo5RBawFyH3GeVN" + "bzz-raw://f099f912010a38e63b1f3c6208bc7b605e59b9dd42bde020cb603dc4f73ce754", + "dweb:/ipfs/QmcP1qHd6wTcPh7xBMvWTbeWE3Ms8vmCSRsyKwkymiTNuW" ] }, "metadata": { @@ -16782,10 +16773,10 @@ }, "sources": { "ProxyERC20.sol": { - "keccak256": "0xfb133acce922041ba6b061ee7a8ce32c7908b0cbb37f343dd9fd81d532999bd8", + "keccak256": "0xa4731706c3292ed368ded616be2fcf28877d8a853cbce27be7d78e6a57636e9f", "urls": [ - "bzz-raw://9ea8edaed10b21ff232e019b44be802821ef5c62b47888b81d19c7232280ccc8", - "dweb:/ipfs/QmNvmS5845T4XjAsUms9WLHDjGxDRRuHo5RBawFyH3GeVN" + "bzz-raw://f099f912010a38e63b1f3c6208bc7b605e59b9dd42bde020cb603dc4f73ce754", + "dweb:/ipfs/QmcP1qHd6wTcPh7xBMvWTbeWE3Ms8vmCSRsyKwkymiTNuW" ] } }, diff --git a/publish/deployed/mainnet/feeds.json b/publish/deployed/mainnet/feeds.json index c5bbe64b60..84c9d27fd5 100644 --- a/publish/deployed/mainnet/feeds.json +++ b/publish/deployed/mainnet/feeds.json @@ -31,6 +31,10 @@ "asset": "DEFI", "feed": "0xa8E875F94138B0C5b51d1e1d5dE35bbDdd28EA87" }, + "ETHBTC": { + "asset": "ETHBTC", + "feed": "0xAc559F25B1619171CbC396a50854A3240b6A4e99" + }, "EUR": { "asset": "EUR", "feed": "0xb49f677943BC038e9857d61E7d053CaA2C1734C1" diff --git a/publish/deployed/mainnet/synths.json b/publish/deployed/mainnet/synths.json index 4d080168ff..2990a2a199 100644 --- a/publish/deployed/mainnet/synths.json +++ b/publish/deployed/mainnet/synths.json @@ -64,6 +64,11 @@ "asset": "DOT", "subclass": "MultiCollateralSynth" }, + { + "name": "sETHBTC", + "asset": "ETHBTC", + "subclass": "MultiCollateralSynth" + }, { "name": "sDEFI", "asset": "DEFI", diff --git a/publish/deployed/mainnet/versions.json b/publish/deployed/mainnet/versions.json index 21b7af55eb..d55965b4c7 100644 --- a/publish/deployed/mainnet/versions.json +++ b/publish/deployed/mainnet/versions.json @@ -3890,5 +3890,30 @@ "keccak256": "0x582cac91f50cfefc154d67097081d0dd0d4877333df51c3cfe19485f80ef7e74" } } + }, + "v2.56.1": { + "tag": "v2.56.1", + "fulltag": "v2.56.1", + "release": "Alhena", + "network": "mainnet", + "date": "2021-12-15T18:16:59-05:00", + "commit": "324105690195d2c0925ffbfffe5d0bba8e98fad7", + "contracts": { + "TokenStatesETHBTC": { + "address": "0x042A7A0022A7695454ac5Be77a4860e50c9683fC", + "status": "current", + "keccak256": "0x10a63d041fa9899b429b12dddcf047b55c23fe62019c08abbba9fa1f603738d3" + }, + "ProxysETHBTC": { + "address": "0x104eDF1da359506548BFc7c25bA1E28C16a70235", + "status": "current", + "keccak256": "0xa4731706c3292ed368ded616be2fcf28877d8a853cbce27be7d78e6a57636e9f" + }, + "SynthsETHBTC": { + "address": "0xcc3aab773e2171b2E257Ee17001400eE378aa52B", + "status": "current", + "keccak256": "0x77d6d75f0faee02ff7a6bae37e0aa47e6afb849484a1f4ea6794131ffc5c77b8" + } + } } } diff --git a/publish/releases.json b/publish/releases.json index ffba79b704..5d97117820 100644 --- a/publish/releases.json +++ b/publish/releases.json @@ -413,6 +413,12 @@ "sources": ["DebtCache", "Issuer"], "released": "both" }, + { + "sip": 188, + "layer": "base", + "sources": [], + "released": "base" + }, { "sip": 192, "layer": "both", @@ -422,7 +428,19 @@ { "sip": 194, "layer": "ovm", - "sources": ["Synthetix"] + "sources": ["Synthetix"], + "released": "ovm" + }, + { + "sip": 195, + "layer": "ovm", + "sources": ["CollateralEth"], + "released": "ovm" + }, + { + "sip": 196, + "layer": "both", + "sources": ["ExchangeRates"] } ], "releases": [ @@ -736,22 +754,22 @@ }, { "name": "Alhena", - "released": false, + "released": true, "version": { "major": 2, "minor": 56 }, - "sips": [] + "sips": [188] }, { "name": "Alhena (Optimism)", "ovm": true, - "released": false, + "released": true, "version": { "major": 2, "minor": 56 }, - "sips": [] + "sips": [194, 195] }, { "name": "Peacock", diff --git a/publish/src/commands/deploy/configure-loans.js b/publish/src/commands/deploy/configure-loans.js index 38324c8966..998d2cd443 100644 --- a/publish/src/commands/deploy/configure-loans.js +++ b/publish/src/commands/deploy/configure-loans.js @@ -34,11 +34,11 @@ module.exports = async ({ console.log(gray(`\n------ INITIALISING MULTI COLLATERAL ------\n`)); - if (CollateralShort && CollateralManager) { - let CollateralsArg = [CollateralShort].map(addressOf); - if (CollateralEth && CollateralErc20) { - CollateralsArg = [CollateralEth, CollateralErc20, CollateralShort].map(addressOf); - } + if (CollateralManager) { + const CollateralsArg = [CollateralShort, CollateralEth, CollateralErc20] + .filter(contract => !!contract) + .map(addressOf); + await runStep({ contract: 'CollateralManager', target: CollateralManager, diff --git a/publish/src/commands/deploy/configure-system-settings.js b/publish/src/commands/deploy/configure-system-settings.js index 8213638635..e182bc66e0 100644 --- a/publish/src/commands/deploy/configure-system-settings.js +++ b/publish/src/commands/deploy/configure-system-settings.js @@ -332,14 +332,16 @@ module.exports = async ({ comment: 'Set the fee rate for minting sETH from ETH in the EtherWrapper (SIP-112)', }); + // Disable checking this as now the current value is set to 0 + const etherWrapperBurnFeeRate = await getDeployParameter('ETHER_WRAPPER_BURN_FEE_RATE'); await runStep({ contract: 'SystemSettings', target: SystemSettings, read: 'etherWrapperBurnFeeRate', readTarget: previousSystemSettings, - expected: input => input !== '0', // only change if zero + expected: input => etherWrapperBurnFeeRate === '0' || input !== '0', // only change if the value to set is above zero and the value onchain is 0 write: 'setEtherWrapperBurnFeeRate', - writeArg: await getDeployParameter('ETHER_WRAPPER_BURN_FEE_RATE'), + writeArg: etherWrapperBurnFeeRate, comment: 'Set the fee rate for burning sETH for ETH in the EtherWrapper (SIP-112)', }); diff --git a/publish/src/commands/deploy/deploy-core.js b/publish/src/commands/deploy/deploy-core.js index b1f190d137..b611aea6dc 100644 --- a/publish/src/commands/deploy/deploy-core.js +++ b/publish/src/commands/deploy/deploy-core.js @@ -14,7 +14,6 @@ module.exports = async ({ currentSynthetixSupply, currentWeekOfInflation, deployer, - oracleAddress, useOvm, }) => { console.log(gray(`\n------ DEPLOY LIBRARIES ------\n`)); @@ -63,7 +62,7 @@ module.exports = async ({ await deployer.deployContract({ name: 'ExchangeRates', source: useOvm ? 'ExchangeRates' : 'ExchangeRatesWithDexPricing', - args: [account, oracleAddress, addressOf(readProxyForResolver), [], []], + args: [account, addressOf(readProxyForResolver)], }); await deployer.deployContract({ diff --git a/publish/src/commands/deploy/index.js b/publish/src/commands/deploy/index.js index 686982fa01..b24cd46e27 100644 --- a/publish/src/commands/deploy/index.js +++ b/publish/src/commands/deploy/index.js @@ -62,7 +62,6 @@ const deploy = async ({ ignoreSafetyChecks, manageNonces, network = DEFAULTS.network, - oracleExrates, privateKey, providerUrl, skipFeedChecks = false, @@ -212,7 +211,6 @@ const deploy = async ({ currentSynthetixSupply, currentLastMintEvent, currentWeekOfInflation, - oracleAddress, systemSuspended, } = await systemAndParameterCheck({ account, @@ -229,7 +227,6 @@ const deploy = async ({ maxPriorityFeePerGas, getDeployParameter, network, - oracleExrates, providerUrl, skipFeedChecks, standaloneFeeds, @@ -276,7 +273,6 @@ const deploy = async ({ currentSynthetixSupply, currentWeekOfInflation, deployer, - oracleAddress, useOvm, }); diff --git a/publish/src/commands/deploy/rebuild-resolver-caches.js b/publish/src/commands/deploy/rebuild-resolver-caches.js index 5194315d21..24a69526bf 100644 --- a/publish/src/commands/deploy/rebuild-resolver-caches.js +++ b/publish/src/commands/deploy/rebuild-resolver-caches.js @@ -66,7 +66,7 @@ module.exports = async ({ ]); // interface doesn't matter as long as it responds to MixinResolver } } catch (err) { - if (/eth_getLogs are limited to a 10,000 blocks range/.test(err.message)) { + if (/limited to a 10,000 blocks range/.test(err.message)) { console.log( yellow.bold( 'Warning: Cannot fetch logs on this network. Known limitation on OVM mainnet - cannot search back greater than 10k blocks' @@ -219,7 +219,7 @@ module.exports = async ({ } } - const addressesChunkSize = useOvm ? 5 : 20; + const addressesChunkSize = 20; let batchCounter = 1; for (let i = 0; i < contractsToRebuildCache.length; i += addressesChunkSize) { const chunk = contractsToRebuildCache.slice(i, i + addressesChunkSize); diff --git a/publish/src/commands/deploy/system-and-parameter-check.js b/publish/src/commands/deploy/system-and-parameter-check.js index ac835a43c2..c14394ab25 100644 --- a/publish/src/commands/deploy/system-and-parameter-check.js +++ b/publish/src/commands/deploy/system-and-parameter-check.js @@ -33,7 +33,6 @@ module.exports = async ({ maxPriorityFeePerGas, getDeployParameter, network, - oracleExrates, providerUrl, skipFeedChecks, standaloneFeeds, @@ -43,7 +42,6 @@ module.exports = async ({ yes, buildPath, }) => { - let oracleAddress; let currentSynthetixSupply; let oldExrates; let currentLastMintEvent; @@ -92,12 +90,8 @@ module.exports = async ({ try { oldExrates = deployer.getExistingContract({ contract: 'ExchangeRates' }); - if (!oracleExrates) { - oracleAddress = await oldExrates.oracle(); - } } catch (err) { if (freshDeploy) { - oracleAddress = oracleExrates || account; oldExrates = undefined; // unset to signify that a fresh one will be deployed } else { console.error( @@ -127,12 +121,10 @@ module.exports = async ({ } } - for (const address of [account, oracleAddress]) { - if (!isAddress(address)) { - console.error(red('Invalid address detected (please check your inputs):', address)); - process.exitCode = 1; - process.exit(); - } + if (!isAddress(account)) { + console.error(red('Invalid address detected (please check your inputs):', account)); + process.exitCode = 1; + process.exit(); } const newSynthsToAdd = synths @@ -206,7 +198,6 @@ module.exports = async ({ : yellow('âš  NO'), 'Deployer account:': account, 'Synthetix totalSupply': `${Math.round(formatUnits(currentSynthetixSupply) / 1e6)}m`, - 'ExchangeRates Oracle': oracleAddress, 'Last Mint Event': `${currentLastMintEvent} (${new Date(currentLastMintEvent * 1000)})`, 'Current Weeks Of Inflation': currentWeekOfInflation, 'Aggregated Prices': aggregatedPriceResults, @@ -240,7 +231,6 @@ module.exports = async ({ currentLastMintEvent, currentWeekOfInflation, oldExrates, - oracleAddress, systemSuspended, }; }; diff --git a/publish/src/commands/owner.js b/publish/src/commands/owner.js index 606bb3af9f..f66bce6bf6 100644 --- a/publish/src/commands/owner.js +++ b/publish/src/commands/owner.js @@ -40,6 +40,7 @@ const owner = async ({ useOvm, useFork, providerUrl, + skipOwnership = false, throwOnNotNominatedOwner = false, }) => { ensureNetwork(network); @@ -239,91 +240,95 @@ const owner = async ({ } } - console.log(gray('Looking for contracts whose ownership we should accept')); const warnings = []; - // prevent dupes if some contracts are in there twice (looking at you ProxyERC20 and ProxyERC20sUSD) - const appendedOwnerCache = {}; - for (const contract of Object.keys(config)) { - if (!deployment.targets[contract]) { - const msg = yellow(`WARNING: contract ${contract} not found in deployment file`); - console.log(msg); - warnings.push(msg); - continue; - } - const { address, source } = deployment.targets[contract]; - const { abi } = deployment.sources[source]; - const deployedContract = new ethers.Contract(address, abi, provider); - - // ignore contracts that don't support Owned - if (!deployedContract.functions.owner) { - continue; - } - const currentOwner = (await deployedContract.owner()).toLowerCase(); - const nominatedOwner = (await deployedContract.nominatedOwner()).toLowerCase(); - - if (currentOwner === newOwner.toLowerCase()) { - console.log(gray(`${newOwner} is already the owner of ${contract} ${address}`)); - } else if (nominatedOwner === newOwner.toLowerCase()) { - const encodedData = deployedContract.interface.encodeFunctionData('acceptOwnership', []); - - if (address in appendedOwnerCache) { - console.log(gray('Skipping as this action is already in the batch')); + if (!skipOwnership) { + console.log(gray('Looking for contracts whose ownership we should accept')); + // prevent dupes if some contracts are in there twice (looking at you ProxyERC20 and ProxyERC20sUSD) + const appendedOwnerCache = {}; + for (const contract of Object.keys(config)) { + if (!deployment.targets[contract]) { + const msg = yellow(`WARNING: contract ${contract} not found in deployment file`); + console.log(msg); + warnings.push(msg); continue; - } else { - appendedOwnerCache[address] = true; } + const { address, source } = deployment.targets[contract]; + const { abi } = deployment.sources[source]; + const deployedContract = new ethers.Contract(address, abi, provider); - if (safeBatchSubmitter && !useFork) { - console.log( - gray(`Attempting to append`, yellow(`${contract}.acceptOwnership()`), `to the batch`) - ); - const { appended } = await safeBatchSubmitter.appendTransaction({ - to: address, - data: encodedData, - }); - if (!appended) { - console.log(gray('Skipping adding to the batch as already in pending queue')); + // ignore contracts that don't support Owned + if (!deployedContract.functions.owner) { + continue; + } + const currentOwner = (await deployedContract.owner()).toLowerCase(); + const nominatedOwner = (await deployedContract.nominatedOwner()).toLowerCase(); + + if (currentOwner === newOwner.toLowerCase()) { + console.log(gray(`${newOwner} is already the owner of ${contract} ${address}`)); + } else if (nominatedOwner === newOwner.toLowerCase()) { + const encodedData = deployedContract.interface.encodeFunctionData('acceptOwnership', []); + + if (address in appendedOwnerCache) { + console.log(gray('Skipping as this action is already in the batch')); + continue; + } else { + appendedOwnerCache[address] = true; } - } else if (relayers) { - // Relayer - console.log( - gray('Adding'), - yellow(`${contract}.acceptOwnership()`), - gray('to the relayer actions') - ); - relayers.actions.push({ target: address, data: encodedData }); - } else { - try { - await confirmOrEnd(gray(`Confirm: Submit`, yellow(`${contract}.acceptOwnership()`), `?`)); - const params = await assignGasOptions({ - tx: { - to: address, - data: encodedData, - }, - provider, - maxFeePerGas, - maxPriorityFeePerGas, + if (safeBatchSubmitter && !useFork) { + console.log( + gray(`Attempting to append`, yellow(`${contract}.acceptOwnership()`), `to the batch`) + ); + const { appended } = await safeBatchSubmitter.appendTransaction({ + to: address, + data: encodedData, }); - - if (gasLimit) { - params.gasLimit = ethers.BigNumber.from(gasLimit); + if (!appended) { + console.log(gray('Skipping adding to the batch as already in pending queue')); + } + } else if (relayers) { + // Relayer + console.log( + gray('Adding'), + yellow(`${contract}.acceptOwnership()`), + gray('to the relayer actions') + ); + relayers.actions.push({ target: address, data: encodedData }); + } else { + try { + await confirmOrEnd( + gray(`Confirm: Submit`, yellow(`${contract}.acceptOwnership()`), `?`) + ); + + const params = await assignGasOptions({ + tx: { + to: address, + data: encodedData, + }, + provider, + maxFeePerGas, + maxPriorityFeePerGas, + }); + + if (gasLimit) { + params.gasLimit = ethers.BigNumber.from(gasLimit); + } + + const tx = await signer.sendTransaction(params); + const receipt = await tx.wait(); + + logTx(receipt); + } catch (err) { + throw Error(`Transaction failed to submit.\n${err}`); } - - const tx = await signer.sendTransaction(params); - const receipt = await tx.wait(); - - logTx(receipt); - } catch (err) { - throw Error(`Transaction failed to submit.\n${err}`); } - } - } else { - const msg = `Cannot acceptOwnership on ${contract} as nominatedOwner: ${nominatedOwner} isn't the newOwner ${newOwner} you specified. Have you run the nominate command yet?`; - if (throwOnNotNominatedOwner && contract !== 'DappMaintenance') { - throw Error(msg); } else { - console.log(cyan(msg)); + const msg = `Cannot acceptOwnership on ${contract} as nominatedOwner: ${nominatedOwner} isn't the newOwner ${newOwner} you specified. Have you run the nominate command yet?`; + if (throwOnNotNominatedOwner && contract !== 'DappMaintenance') { + throw Error(msg); + } else { + console.log(cyan(msg)); + } } } } @@ -468,6 +473,7 @@ module.exports = { .option('--max-priority-fee-per-gas ', 'Priority gas fee price in GWEI', '1') .option('-l, --gas-limit ', 'Gas limit', parseInt, DEFAULTS.gasLimit) .option('-n, --network ', 'The network to run off.', x => x.toLowerCase(), 'kovan') + .option('-s, --skip-ownership', 'Skip ownership checks.') .option('-y, --yes', 'Dont prompt, just reply yes.') .option('-z, --use-ovm', 'Target deployment for the OVM (Optimism).') .option( diff --git a/test/contracts/BaseSynthetix.js b/test/contracts/BaseSynthetix.js index 366d9206c3..18959c8ae1 100644 --- a/test/contracts/BaseSynthetix.js +++ b/test/contracts/BaseSynthetix.js @@ -10,11 +10,13 @@ require('./common'); // import common test scaffolding const { setupContract, setupAllContracts } = require('./setup'); -const { currentTime, fastForward, toUnit } = require('../utils')(); +const { fastForward, toUnit } = require('../utils')(); const { ensureOnlyExpectedMutativeFunctions, onlyGivenAddressCanInvoke, + setupPriceAggregators, + updateAggregatorRates, updateRatesWithDefaults, setStatus, } = require('./helpers'); @@ -33,8 +35,6 @@ contract('BaseSynthetix', async accounts => { exchangeRates, debtCache, escrow, - oracle, - timestamp, addressResolver, systemSettings, systemStatus; @@ -68,9 +68,7 @@ contract('BaseSynthetix', async accounts => { ], })); - // Send a price update to guarantee we're not stale. - oracle = account1; - timestamp = await currentTime(); + await setupPriceAggregators(exchangeRates, owner, [sAUD, sEUR, sETH]); }); addSnapshotBeforeRestoreAfterEach(); @@ -406,7 +404,7 @@ contract('BaseSynthetix', async accounts => { }); describe('when a user has exchanged into sETH', () => { beforeEach(async () => { - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); await baseSynthetix.issueSynths(toUnit('100'), { from: owner }); await baseSynthetix.exchange(sUSD, toUnit('10'), sETH, { from: owner }); @@ -434,13 +432,10 @@ contract('BaseSynthetix', async accounts => { // fast forward to get past initial SNX setting await fastForward((await exchangeRates.rateStalePeriod()).add(web3.utils.toBN('300'))); - timestamp = await currentTime(); - - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH], - ['0.5', '1.25', '100'].map(toUnit), - timestamp, - { from: oracle } + ['0.5', '1.25', '100'].map(toUnit) ); await debtCache.takeDebtSnapshot(); }); @@ -449,9 +444,7 @@ contract('BaseSynthetix', async accounts => { }); describe('when SNX is also set', () => { beforeEach(async () => { - timestamp = await currentTime(); - - await exchangeRates.updateRates([SNX], ['1'].map(toUnit), timestamp, { from: oracle }); + await updateAggregatorRates(exchangeRates, [SNX], ['1'].map(toUnit)); }); it('then no stale rates', async () => { assert.equal(await baseSynthetix.anySynthOrSNXRateIsInvalid(), false); @@ -461,11 +454,7 @@ contract('BaseSynthetix', async accounts => { beforeEach(async () => { await fastForward((await exchangeRates.rateStalePeriod()).add(web3.utils.toBN('300'))); - timestamp = await currentTime(); - - await exchangeRates.updateRates([SNX, sAUD], ['0.1', '0.78'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX, sAUD], ['0.1', '0.78'].map(toUnit)); }); it('then anySynthOrSNXRateIsInvalid() returns true', async () => { @@ -522,7 +511,7 @@ contract('BaseSynthetix', async accounts => { beforeEach(async () => { // Ensure all synths have rates to allow issuance - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); }); it('should transfer using the ERC20 transfer function @gasprofile', async () => { @@ -707,28 +696,21 @@ contract('BaseSynthetix', async accounts => { it('should not allow transfer if the exchange rate for SNX is stale', async () => { await ensureTransferReverts(); - const timestamp = await currentTime(); - // now give some synth rates - await exchangeRates.updateRates([sAUD, sEUR], ['0.5', '1.25'].map(toUnit), timestamp, { - from: oracle, - }); + + await updateAggregatorRates(exchangeRates, [sAUD, sEUR], ['0.5', '1.25'].map(toUnit)); await debtCache.takeDebtSnapshot(); await ensureTransferReverts(); // the remainder of the synths have prices - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH], ['100'].map(toUnit)); await debtCache.takeDebtSnapshot(); await ensureTransferReverts(); // now give SNX rate - await exchangeRates.updateRates([SNX], ['1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['1'].map(toUnit)); // now SNX transfer should work await baseSynthetix.transfer(account2, value, { from: account1 }); @@ -740,28 +722,20 @@ contract('BaseSynthetix', async accounts => { it('should not allow transfer if the exchange rate for any synth is stale', async () => { await ensureTransferReverts(); - const timestamp = await currentTime(); - // now give SNX rate - await exchangeRates.updateRates([SNX], ['1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['1'].map(toUnit)); await debtCache.takeDebtSnapshot(); await ensureTransferReverts(); // now give some synth rates - await exchangeRates.updateRates([sAUD, sEUR], ['0.5', '1.25'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sAUD, sEUR], ['0.5', '1.25'].map(toUnit)); await debtCache.takeDebtSnapshot(); await ensureTransferReverts(); // now give the remainder of synths rates - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH], ['100'].map(toUnit)); await debtCache.takeDebtSnapshot(); // now SNX transfer should work @@ -850,8 +824,7 @@ contract('BaseSynthetix', async accounts => { await systemSettings.setExchangeDynamicFeeRounds('0', { from: owner }); // Set sEUR for purposes of this test - const timestamp1 = await currentTime(); - await exchangeRates.updateRates([sEUR], [toUnit('0.75')], timestamp1, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sEUR], [toUnit('0.75')]); await debtCache.takeDebtSnapshot(); const issuedSynthetixs = web3.utils.toBN('200000'); @@ -879,8 +852,7 @@ contract('BaseSynthetix', async accounts => { }); // Increase the value of sEUR relative to synthetix - const timestamp2 = await currentTime(); - await exchangeRates.updateRates([sEUR], [toUnit('2.10')], timestamp2, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sEUR], [toUnit('2.10')]); await debtCache.takeDebtSnapshot(); // Ensure that the new synthetix account1 receives cannot be transferred out. @@ -898,10 +870,9 @@ contract('BaseSynthetix', async accounts => { await systemSettings.setPriceDeviationThresholdFactor(toUnit('5'), { from: owner }); // Set sAUD for purposes of this test - const timestamp1 = await currentTime(); const aud2usdrate = toUnit('2'); - await exchangeRates.updateRates([sAUD], [aud2usdrate], timestamp1, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sAUD], [aud2usdrate]); await debtCache.takeDebtSnapshot(); const issuedSynthetixs = web3.utils.toBN('200000'); @@ -923,9 +894,8 @@ contract('BaseSynthetix', async accounts => { await baseSynthetix.exchange(sUSD, issuedSynths, sAUD, { from: account1 }); // Increase the value of sAUD relative to synthetix - const timestamp2 = await currentTime(); const newAUDExchangeRate = toUnit('1'); - await exchangeRates.updateRates([sAUD], [newAUDExchangeRate], timestamp2, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sAUD], [newAUDExchangeRate]); await debtCache.takeDebtSnapshot(); const transferable2 = await baseSynthetix.transferableSynthetix(account1); diff --git a/test/contracts/CollateralErc20.js b/test/contracts/CollateralErc20.js index 6121bdacad..5e1b4146b6 100644 --- a/test/contracts/CollateralErc20.js +++ b/test/contracts/CollateralErc20.js @@ -8,11 +8,16 @@ const BN = require('bn.js'); const PublicEST8Decimals = artifacts.require('PublicEST8Decimals'); -const { fastForward, toUnit, currentTime } = require('../utils')(); +const { fastForward, toUnit } = require('../utils')(); const { setupAllContracts, setupContract } = require('./setup'); -const { ensureOnlyExpectedMutativeFunctions, setStatus } = require('./helpers'); +const { + ensureOnlyExpectedMutativeFunctions, + setStatus, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { toBytes32, @@ -47,7 +52,7 @@ contract('CollateralErc20', async accounts => { let id; let proxy, tokenState; - const [deployerAccount, owner, oracle, , account1, account2] = accounts; + const [deployerAccount, owner, , , account1, account2] = accounts; let cerc20, managerState, @@ -85,17 +90,7 @@ contract('CollateralErc20', async accounts => { }; const updateRatesWithDefaults = async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); - - const sBTC = toBytes32('sBTC'); - - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH, sBTC], [100, 10000].map(toUnit)); }; const fastForwardAndUpdateRates = async seconds => { @@ -147,6 +142,8 @@ contract('CollateralErc20', async accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sBTC, sETH]); + managerState = await CollateralManagerState.new(owner, ZERO_ADDRESS, { from: deployerAccount }); const maxDebt = toUnit(10000000); @@ -304,28 +301,20 @@ contract('CollateralErc20', async accounts => { }); it('when the price falls by 25% our c ratio is 150%', async () => { - await exchangeRates.updateRates([sBTC], ['7500'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [7500].map(toUnit)); const ratio = await cerc20.collateralRatio(id); assert.bnEqual(ratio, toUnit(1.5)); }); it('when the price increases by 100% our c ratio is 400%', async () => { - await exchangeRates.updateRates([sBTC], ['20000'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sBTC], [20000].map(toUnit)); const ratio = await cerc20.collateralRatio(id); assert.bnEqual(ratio, toUnit(4)); }); it('when the price fallsby 50% our cratio is 100%', async () => { - await exchangeRates.updateRates([sBTC], ['5000'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sBTC], [5000].map(toUnit)); const ratio = await cerc20.collateralRatio(id); assert.bnEqual(ratio, toUnit(1)); }); @@ -346,10 +335,7 @@ contract('CollateralErc20', async accounts => { }); it('price changes should not change the cratio', async () => { - await exchangeRates.updateRates([sBTC], ['75'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sBTC], [75].map(toUnit)); const ratio = await cerc20.collateralRatio(id); assert.bnEqual(ratio, toUnit(2)); }); @@ -909,10 +895,7 @@ contract('CollateralErc20', async accounts => { let liquidationAmount; beforeEach(async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([sBTC], ['7000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [7000].map(toUnit)); await issuesUSDToAccount(toUnit(5000), account2); @@ -962,10 +945,7 @@ contract('CollateralErc20', async accounts => { describe('when a loan needs to be completely liquidated', async () => { beforeEach(async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([sBTC], ['5000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [5000].map(toUnit)); loan = await cerc20.loans(id); diff --git a/test/contracts/CollateralEth.js b/test/contracts/CollateralEth.js index 122337bf79..99635dba55 100644 --- a/test/contracts/CollateralEth.js +++ b/test/contracts/CollateralEth.js @@ -6,11 +6,16 @@ const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); const BN = require('bn.js'); -const { fastForward, getEthBalance, toUnit, fromUnit, currentTime } = require('../utils')(); +const { fastForward, getEthBalance, toUnit, fromUnit } = require('../utils')(); const { setupAllContracts } = require('./setup'); -const { ensureOnlyExpectedMutativeFunctions, setStatus } = require('./helpers'); +const { + ensureOnlyExpectedMutativeFunctions, + setStatus, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { toBytes32 } = require('../..'); @@ -20,6 +25,7 @@ contract('CollateralEth', async accounts => { const sUSD = toBytes32('sUSD'); const sETH = toBytes32('sETH'); + const sBTC = toBytes32('sBTC'); const oneETH = toUnit(1); const twoETH = toUnit(2); @@ -36,7 +42,7 @@ contract('CollateralEth', async accounts => { let loan; let id; - const [, owner, oracle, account1, account2] = accounts; + const [, owner, , account1, account2] = accounts; let ceth, managerState, @@ -101,6 +107,8 @@ contract('CollateralEth', async accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sBTC, sETH]); + await managerState.setAssociatedContract(manager.address, { from: owner }); FEE_ADDRESS = await feePool.FEE_ADDRESS(); @@ -139,17 +147,7 @@ contract('CollateralEth', async accounts => { }; const updateRatesWithDefaults = async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); - - const sBTC = toBytes32('sBTC'); - - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH, sBTC], [100, 10000].map(toUnit)); }; const fastForwardAndUpdateRates = async seconds => { @@ -219,28 +217,19 @@ contract('CollateralEth', async accounts => { }); it('when the price falls by 25% our c ratio is 150%', async () => { - await exchangeRates.updateRates([sETH], ['75'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(75)]); const ratio = await ceth.collateralRatio(id); assert.bnEqual(ratio, toUnit(1.5)); }); it('when the price increases by 100% our c ratio is 400%', async () => { - await exchangeRates.updateRates([sETH], ['200'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(200)]); const ratio = await ceth.collateralRatio(id); assert.bnEqual(ratio, toUnit(4)); }); it('when the price falls by 50% our cratio is 100%', async () => { - await exchangeRates.updateRates([sETH], ['50'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(50)]); const ratio = await ceth.collateralRatio(id); assert.bnEqual(ratio, toUnit(1)); }); @@ -261,10 +250,7 @@ contract('CollateralEth', async accounts => { }); it('price changes should not change the cratio', async () => { - await exchangeRates.updateRates([sETH], ['75'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(75)]); const ratio = await ceth.collateralRatio(id); assert.bnEqual(ratio, toUnit(2)); }); @@ -279,7 +265,7 @@ contract('CollateralEth', async accounts => { assert.bnClose(sUSDAmount, toUnit('200'), '100'); // $260 worth of eth should allow $200 (0.02) of sBTC to be issued. - const sBTCAmount = await ceth.maxLoan(toUnit('2.6'), toBytes32('sBTC')); + const sBTCAmount = await ceth.maxLoan(toUnit('2.6'), sBTC); assert.bnEqual(sBTCAmount, toUnit('0.02')); }); @@ -791,11 +777,7 @@ contract('CollateralEth', async accounts => { let liquidationAmount; beforeEach(async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['90'].map(toUnit), timestamp, { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(90)]); await issuesUSDToAccount(toUnit(1000), account2); liquidatorEthBalBefore = new BN(await getEthBalance(account2)); @@ -856,11 +838,7 @@ contract('CollateralEth', async accounts => { let liquidatorEthBalBefore; beforeEach(async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['50'].map(toUnit), timestamp, { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(50)]); loan = await ceth.loans(id); await issuesUSDToAccount(toUnit(1000), account2); diff --git a/test/contracts/CollateralManager.js b/test/contracts/CollateralManager.js index 9b6db8a531..ffa1634309 100644 --- a/test/contracts/CollateralManager.js +++ b/test/contracts/CollateralManager.js @@ -4,11 +4,16 @@ const { contract } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { toUnit, currentTime, fastForward } = require('../utils')(); +const { toUnit, fastForward } = require('../utils')(); const { setupAllContracts, setupContract, mockToken } = require('./setup'); -const { ensureOnlyExpectedMutativeFunctions, onlyGivenAddressCanInvoke } = require('./helpers'); +const { + ensureOnlyExpectedMutativeFunctions, + onlyGivenAddressCanInvoke, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { toBytes32, @@ -16,7 +21,7 @@ const { } = require('../..'); contract('CollateralManager', async accounts => { - const [, owner, oracle, , account1] = accounts; + const [, owner, , , account1] = accounts; const sETH = toBytes32('sETH'); const sUSD = toBytes32('sUSD'); @@ -58,17 +63,7 @@ contract('CollateralManager', async accounts => { }; const updateRatesWithDefaults = async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); - - const sBTC = toBytes32('sBTC'); - - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH, sBTC], [100, 10000].map(toUnit)); }; const fastForwardAndUpdateRates = async seconds => { @@ -127,6 +122,8 @@ contract('CollateralManager', async accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sBTC, sETH]); + maxDebt = toUnit(50000000); await managerState.setAssociatedContract(manager.address, { from: owner }); diff --git a/test/contracts/CollateralShort.js b/test/contracts/CollateralShort.js index 013a51e3e5..24bb6dd32d 100644 --- a/test/contracts/CollateralShort.js +++ b/test/contracts/CollateralShort.js @@ -4,11 +4,16 @@ const { contract } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { fastForward, toUnit, fromUnit, currentTime } = require('../utils')(); +const { fastForward, toUnit, fromUnit } = require('../utils')(); const { setupAllContracts } = require('./setup'); -const { ensureOnlyExpectedMutativeFunctions, setExchangeFeeRateForSynths } = require('./helpers'); +const { + ensureOnlyExpectedMutativeFunctions, + setExchangeFeeRateForSynths, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { toBytes32, @@ -22,7 +27,7 @@ contract('CollateralShort', async accounts => { const sETH = toBytes32('sETH'); const sBTC = toBytes32('sBTC'); - const [, owner, oracle, , account1, account2] = accounts; + const [, owner, , , account1, account2] = accounts; let short, managerState, @@ -57,21 +62,10 @@ contract('CollateralShort', async accounts => { }; const updateRatesWithDefaults = async () => { - let timestamp; - for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); - } - const sBTC = toBytes32('sBTC'); for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH, sBTC], [100, 10000].map(toUnit)); } }; @@ -111,6 +105,8 @@ contract('CollateralShort', async accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sBTC, sETH]); + await managerState.setAssociatedContract(manager.address, { from: owner }); FEE_ADDRESS = await feePool.FEE_ADDRESS(); @@ -514,10 +510,7 @@ contract('CollateralShort', async accounts => { await fastForwardAndUpdateRates(3600); - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['50'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(50)]); // simulate buying sETH for 50 susd. await sUSDSynth.transfer(owner, toUnit(50), { from: account1 }); @@ -539,10 +532,7 @@ contract('CollateralShort', async accounts => { await fastForwardAndUpdateRates(3600); - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['150'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(150)]); // simulate buying sETH for 150 susd. await sUSDSynth.transfer(owner, toUnit(150), { from: account1 }); @@ -574,10 +564,7 @@ contract('CollateralShort', async accounts => { }); it('liquidation should be capped to only fix the c ratio', async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['110'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(110)]); // When the ETH price increases 10% to $110, the short // which started at 130% should allow 0.18 ETH @@ -628,11 +615,7 @@ contract('CollateralShort', async accounts => { await fastForwardAndUpdateRates(3600); - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['150'].map(toUnit), timestamp, { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(150)]); await debtCache.takeDebtSnapshot(); result = await debtCache.cachedDebt(); assert.bnEqual(result, toUnit(111100)); @@ -673,10 +656,7 @@ contract('CollateralShort', async accounts => { await fastForwardAndUpdateRates(3600); - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['150'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(150)]); // 111100 + 50 - (2 * 50) = 111,050 @@ -720,10 +700,7 @@ contract('CollateralShort', async accounts => { await fastForwardAndUpdateRates(3600); - const timestamp = await currentTime(); - await exchangeRates.updateRates([sETH], ['50'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH], [toUnit(50)]); // 111100 - 50 + (2 * 50) = 111,150 diff --git a/test/contracts/CollateralUtil.js b/test/contracts/CollateralUtil.js index b3c1c848a8..767d17a8a6 100644 --- a/test/contracts/CollateralUtil.js +++ b/test/contracts/CollateralUtil.js @@ -4,11 +4,15 @@ const { contract, web3 } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { toUnit, currentTime } = require('../utils')(); +const { toUnit } = require('../utils')(); const { setupAllContracts, setupContract, mockToken } = require('./setup'); -const { ensureOnlyExpectedMutativeFunctions } = require('./helpers'); +const { + ensureOnlyExpectedMutativeFunctions, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { toBytes32 } = require('../..'); @@ -27,7 +31,7 @@ contract('CollateralUtil', async accounts => { const name = 'Some name'; const symbol = 'TOKEN'; - const [, owner, oracle, , account1] = accounts; + const [, owner, , , account1] = accounts; let cerc20, managerState, @@ -63,20 +67,6 @@ contract('CollateralUtil', async accounts => { await renBTC.transfer(receiver, issueAmount, { from: owner }); }; - const updateRatesWithDefaults = async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); - - const sBTC = toBytes32('sBTC'); - - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); - }; - const deployCollateral = async ({ owner, manager, @@ -125,6 +115,8 @@ contract('CollateralUtil', async accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sBTC, sETH]); + await managerState.setAssociatedContract(manager.address, { from: owner }); ({ token: renBTC } = await mockToken({ @@ -186,7 +178,7 @@ contract('CollateralUtil', async accounts => { addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { - await updateRatesWithDefaults(); + await updateAggregatorRates(exchangeRates, [sETH, sBTC], [100, 10000].map(toUnit)); await issuesUSDToAccount(toUnit(1000), owner); await issuesBTCtoAccount(toUnit(10), owner); @@ -224,9 +216,7 @@ contract('CollateralUtil', async accounts => { }); it('when we start at 200%, we can take a 25% reduction in collateral prices', async () => { - await exchangeRates.updateRates([sBTC], ['7500'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [toUnit(7500)]); amountToLiquidate = await cerc20.liquidationAmount(id); @@ -234,9 +224,7 @@ contract('CollateralUtil', async accounts => { }); it('when we start at 200%, a price shock of 30% in the collateral requires 25% of the loan to be liquidated', async () => { - await exchangeRates.updateRates([sBTC], ['7000'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [toUnit(7000)]); amountToLiquidate = await cerc20.liquidationAmount(id); @@ -244,9 +232,7 @@ contract('CollateralUtil', async accounts => { }); it('when we start at 200%, a price shock of 40% in the collateral requires 75% of the loan to be liquidated', async () => { - await exchangeRates.updateRates([sBTC], ['6000'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [toUnit(6000)]); amountToLiquidate = await cerc20.liquidationAmount(id); @@ -254,10 +240,7 @@ contract('CollateralUtil', async accounts => { }); it('when we start at 200%, a price shock of 45% in the collateral requires 100% of the loan to be liquidated', async () => { - await exchangeRates.updateRates([sBTC], ['5500'].map(toUnit), await currentTime(), { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [sBTC], [toUnit(5500)]); amountToLiquidate = await cerc20.liquidationAmount(id); assert.bnClose(amountToLiquidate, toUnit(5000), '10000'); @@ -279,9 +262,7 @@ contract('CollateralUtil', async accounts => { }); it('when BTC is @ $20000 and we are liquidating 1000 sUSD, then redeem 0.055 BTC', async () => { - await exchangeRates.updateRates([sBTC], ['20000'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [toUnit(20000)]); collateralRedeemed = await util.collateralRedeemed(sUSD, oneThousandsUSD, collateralKey); @@ -289,9 +270,7 @@ contract('CollateralUtil', async accounts => { }); it('when BTC is @ $7000 and we are liquidating 2500 sUSD, then redeem 0.36666 ETH', async () => { - await exchangeRates.updateRates([sBTC], ['7000'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [toUnit(7000)]); collateralRedeemed = await util.collateralRedeemed(sUSD, toUnit(2500), collateralKey); @@ -303,9 +282,7 @@ contract('CollateralUtil', async accounts => { assert.bnEqual(collateralRedeemed, toUnit(1.1)); - await exchangeRates.updateRates([sBTC], ['1000'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], [toUnit(1000)]); collateralRedeemed = await util.collateralRedeemed(sBTC, toUnit(1), collateralKey); diff --git a/test/contracts/DebtCache.js b/test/contracts/DebtCache.js index 003608713b..d1b69db97e 100644 --- a/test/contracts/DebtCache.js +++ b/test/contracts/DebtCache.js @@ -15,6 +15,8 @@ const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions, setStatus, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { @@ -35,7 +37,7 @@ contract('DebtCache', async accounts => { ].map(toBytes32); const synthKeys = [sUSD, sAUD, sEUR, sETH, SNX]; - const [deployerAccount, owner, oracle, account1, account2] = accounts; + const [deployerAccount, owner, , account1, account2] = accounts; const oneETH = toUnit('1.0'); const twoETH = toUnit('2.0'); @@ -49,7 +51,6 @@ contract('DebtCache', async accounts => { sETHContract, sEURContract, sAUDContract, - timestamp, debtCache, issuer, synths, @@ -279,23 +280,21 @@ contract('DebtCache', async accounts => { 'WETH', ], })); + + await setupPriceAggregators(exchangeRates, owner, [sAUD, sEUR, sETH, ETH, iETH]); }); addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, SNX, sETH, ETH, iETH], - ['0.5', '1.25', '10', '200', '200', '200'].map(toUnit), - timestamp, - { from: oracle } + ['0.5', '1.25', '10', '200', '200', '200'].map(toUnit) ); } - // set a 0.3% default exchange fee rate const exchangeFeeRate = toUnit('0.003'); await setExchangeFeeRateForSynths({ owner, @@ -397,11 +396,10 @@ contract('DebtCache', async accounts => { // set default issuance ratio of 0.2 await systemSettings.setIssuanceRatio(toUnit('0.2'), { from: owner }); // set up initial prices - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH], - ['0.5', '2', '100'].map(toUnit), - await currentTime(), - { from: oracle } + ['0.5', '2', '100'].map(toUnit) ); await debtCache.takeDebtSnapshot(); @@ -453,9 +451,7 @@ contract('DebtCache', async accounts => { assert.bnEqual(result[0], toUnit(550)); assert.isFalse(result[1]); - await exchangeRates.updateRates([sAUD, sEUR], ['1', '3'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sAUD, sEUR], ['1', '3'].map(toUnit)); await debtCache.takeDebtSnapshot(); assert.bnEqual((await debtCache.cacheInfo()).debt, toUnit(700)); result = await debtCache.currentDebt(); @@ -477,13 +473,10 @@ contract('DebtCache', async accounts => { }); it('updates the cached values for all individual synths', async () => { - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH], - ['1', '3', '200'].map(toUnit), - await currentTime(), - { - from: oracle, - } + ['1', '3', '200'].map(toUnit) ); await debtCache.takeDebtSnapshot(); let debts = await debtCache.currentSynthDebts([sUSD, sEUR, sAUD, sETH]); @@ -511,11 +504,10 @@ contract('DebtCache', async accounts => { assert.isTrue((await debtCache.cacheInfo()).isInvalid); // Revalidate the cache once rates are no longer stale - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, SNX, sETH, ETH, iETH], - ['0.5', '2', '100', '200', '200', '200'].map(toUnit), - await currentTime(), - { from: oracle } + ['0.5', '2', '100', '200', '200', '200'].map(toUnit) ); const tx2 = await debtCache.takeDebtSnapshot(); assert.isFalse((await debtCache.cacheInfo()).isInvalid); @@ -532,11 +524,10 @@ contract('DebtCache', async accounts => { await fastForward(snapshotStaleTime + 10); // ensure no actual rates are stale. - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH, SNX], - ['0.5', '2', '100', '1'].map(toUnit), - await currentTime(), - { from: oracle } + ['0.5', '2', '100', '1'].map(toUnit) ); const info = await debtCache.cacheInfo(); @@ -600,13 +591,11 @@ contract('DebtCache', async accounts => { const snapshotStaleTime = await systemSettings.debtSnapshotStaleTime(); await fastForward(snapshotStaleTime + 10); // ensure no actual rates are stale. - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH, SNX], - ['0.5', '2', '100', '1'].map(toUnit), - await currentTime(), - { from: oracle } + ['0.5', '2', '100', '1'].map(toUnit) ); - await assert.revert( synthetix.issueSynths(toUnit('10'), { from: account1 }), 'A synth or SNX rate is invalid' @@ -674,13 +663,10 @@ contract('DebtCache', async accounts => { it('allows resynchronisation of subsets of synths', async () => { await debtCache.takeDebtSnapshot(); - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH], - ['1', '3', '200'].map(toUnit), - await currentTime(), - { - from: oracle, - } + ['1', '3', '200'].map(toUnit) ); // First try a single currency, ensuring that the others have not been altered. @@ -714,11 +700,10 @@ contract('DebtCache', async accounts => { assert.isTrue((await debtCache.cacheInfo()).isInvalid); // But even if we update all rates, we can't revalidate the cache using the partial update function - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH], - ['0.5', '2', '100'].map(toUnit), - await currentTime(), - { from: oracle } + ['0.5', '2', '100'].map(toUnit) ); const tx2 = await debtCache.updateCachedSynthDebts([sAUD, sEUR, sETH]); assert.isTrue((await debtCache.cacheInfo()).isInvalid); @@ -729,13 +714,10 @@ contract('DebtCache', async accounts => { it('properly emits events', async () => { await debtCache.takeDebtSnapshot(); - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH], - ['1', '3', '200'].map(toUnit), - await currentTime(), - { - from: oracle, - } + ['1', '3', '200'].map(toUnit) ); const tx = await debtCache.updateCachedSynthDebts([sAUD]); @@ -1006,9 +988,7 @@ contract('DebtCache', async accounts => { const debts = await debtCache.cachedSynthDebts([sAUD, sEUR]); - await exchangeRates.updateRates([sAUD, sEUR], ['1', '1'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sAUD, sEUR], ['1', '1'].map(toUnit)); await synthetix.exchange(sEUR, toUnit(10), sAUD, { from: account1 }); const postDebts = await debtCache.cachedSynthDebts([sAUD, sEUR]); @@ -1043,9 +1023,7 @@ contract('DebtCache', async accounts => { // set a high price deviation threshold factor to be sure it doesn't trigger here await systemSettings.setPriceDeviationThresholdFactor(toUnit('99'), { from: owner }); - await exchangeRates.updateRates([sAUD, sEUR], ['2', '1'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sAUD, sEUR], ['2', '1'].map(toUnit)); await fastForward(100); diff --git a/test/contracts/Depot.js b/test/contracts/Depot.js index 1fafcec800..00ce2420c8 100644 --- a/test/contracts/Depot.js +++ b/test/contracts/Depot.js @@ -5,7 +5,6 @@ const { contract, web3 } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); const { - currentTime, fastForward, getEthBalance, toUnit, @@ -17,6 +16,8 @@ const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions, setStatus, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { mockToken, setupAllContracts } = require('./setup'); @@ -26,7 +27,7 @@ const { toBytes32 } = require('../..'); contract('Depot', async accounts => { let synthetix, synth, depot, addressResolver, systemStatus, exchangeRates, ethRate, snxRate; - const [, owner, oracle, fundsWallet, address1, address2, address3] = accounts; + const [, owner, , fundsWallet, address1, address2, address3] = accounts; const [SNX, ETH] = ['SNX', 'ETH'].map(toBytes32); @@ -71,19 +72,16 @@ contract('Depot', async accounts => { 'Issuer', ], })); + + await setupPriceAggregators(exchangeRates, owner, [ETH]); }); addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { - const timestamp = await currentTime(); - snxRate = toUnit('0.1'); ethRate = toUnit('172'); - - await exchangeRates.updateRates([SNX, ETH], [snxRate, ethRate], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX, ETH], [snxRate, ethRate]); }); it('should set constructor params on deployment', async () => { @@ -778,10 +776,7 @@ contract('Depot', async accounts => { ); }); it('when the purchaser supplies a rate and the rate is changed in by the oracle', async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX, ETH], ['0.1', '134'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX, ETH], ['0.1', '134'].map(toUnit)); await assert.revert( depot.exchangeEtherForSynthsAtRate(ethRate, payload), 'Guaranteed rate would not be received' @@ -830,10 +825,7 @@ contract('Depot', async accounts => { ); }); it('when the purchaser supplies a rate and the rate is changed in by the oracle', async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX, ETH], ['0.1', '134'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX, ETH], ['0.1', '134'].map(toUnit)); await assert.revert( depot.exchangeEtherForSNXAtRate(ethRate, snxRate, ethToSendFromPurchaser), 'Guaranteed ether rate would not be received' @@ -894,10 +886,7 @@ contract('Depot', async accounts => { ); }); it('when the purchaser supplies a rate and the rate is changed in by the oracle', async () => { - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], ['0.05'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['0.05'].map(toUnit)); await assert.revert( depot.exchangeSynthsForSNXAtRate(synthsToSend, snxRate, fromPurchaser), 'Guaranteed rate would not be received' diff --git a/test/contracts/EtherWrapper.js b/test/contracts/EtherWrapper.js index 70e1d612f0..c5b6b105a9 100644 --- a/test/contracts/EtherWrapper.js +++ b/test/contracts/EtherWrapper.js @@ -4,12 +4,14 @@ const { contract } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { currentTime, toUnit, multiplyDecimal } = require('../utils')(); +const { toUnit, multiplyDecimal } = require('../utils')(); const { ensureOnlyExpectedMutativeFunctions, getDecodedLogs, decodedEventEqual, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { setupAllContracts } = require('./setup'); @@ -23,7 +25,7 @@ contract('EtherWrapper', async accounts => { const ONE = toBN('1'); - const [, owner, oracle, , account1] = accounts; + const [, owner, , , account1] = accounts; let systemSettings, feePool, @@ -35,8 +37,7 @@ contract('EtherWrapper', async accounts => { sUSDSynth, sETHSynth, etherWrapper, - weth, - timestamp; + weth; const calculateETHToUSD = async feesInETH => { // Ask the Depot how many sUSD I will get for this ETH @@ -93,12 +94,10 @@ contract('EtherWrapper', async accounts => { await systemSettings.setEtherWrapperBurnFeeRate(toUnit('0.005'), { from: owner }); FEE_ADDRESS = await feePool.FEE_ADDRESS(); - timestamp = await currentTime(); + await setupPriceAggregators(exchangeRates, owner, [sETH, ETH]); // Depot requires ETH rates - await exchangeRates.updateRates([sETH, ETH], ['1500', '1500'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH, ETH], ['1500', '1500'].map(toUnit)); }); addSnapshotBeforeRestoreAfterEach(); diff --git a/test/contracts/ExchangeRates.js b/test/contracts/ExchangeRates.js index 87ca3afd35..c5a78a4cfb 100644 --- a/test/contracts/ExchangeRates.js +++ b/test/contracts/ExchangeRates.js @@ -17,9 +17,11 @@ const { ensureOnlyExpectedMutativeFunctions, onlyGivenAddressCanInvoke, convertToDecimals, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); -const { setupContract, setupAllContracts } = require('./setup'); +const { setupAllContracts } = require('./setup'); const { toBytes32, @@ -31,33 +33,9 @@ const { toBN } = require('web3-utils'); const MockAggregator = artifacts.require('MockAggregatorV2V3'); -const getRandomCurrencyKey = () => - Math.random() - .toString(36) - .substring(2, 6) - .toUpperCase(); - -const createRandomKeysAndRates = quantity => { - const uniqueCurrencyKeys = {}; - for (let i = 0; i < quantity; i++) { - const rate = Math.random() * 100; - const key = toBytes32(getRandomCurrencyKey()); - uniqueCurrencyKeys[key] = web3.utils.toWei(rate.toFixed(18), 'ether'); - } - - const rates = []; - const currencyKeys = []; - Object.entries(uniqueCurrencyKeys).forEach(([key, rate]) => { - currencyKeys.push(key); - rates.push(rate); - }); - - return { currencyKeys, rates }; -}; - contract('Exchange Rates', async accounts => { const [deployerAccount, owner, oracle, dexPriceAggregator, accountOne, accountTwo] = accounts; - const [SNX, sJPY, sETH, sXTZ, sBNB, sUSD, sEUR, sAUD, fastGasPrice] = [ + const [SNX, sJPY, sETH, sXTZ, sBNB, sUSD, sEUR, sAUD, GOLD, fastGasPrice] = [ 'SNX', 'sJPY', 'sETH', @@ -66,6 +44,7 @@ contract('Exchange Rates', async accounts => { 'sUSD', 'sEUR', 'sAUD', + 'GOLD', 'fastGasPrice', ].map(toBytes32); let instance; @@ -73,20 +52,10 @@ contract('Exchange Rates', async accounts => { let aggregatorJPY; let aggregatorXTZ; let aggregatorFastGasPrice; - let initialTime; - let timeSent; - let resolver; let mockFlagsInterface; const itIncludesCorrectMutativeFunctions = contract => { - const baseFunctions = [ - 'addAggregator', - 'deleteRate', - 'removeAggregator', - 'setOracle', - 'updateRates', - 'mutativeEffectiveValueAndRatesAtRound', - ]; + const baseFunctions = ['addAggregator', 'removeAggregator']; const withDexPricingFunctions = baseFunctions.concat(['setDexPriceAggregator']); it('only expected functions should be mutative', () => { @@ -103,497 +72,11 @@ contract('Exchange Rates', async accounts => { describe('constructor', () => { it('should set constructor params on deployment', async () => { assert.equal(await instance.owner(), owner); - assert.equal(await instance.oracle(), oracle); - - assert.etherEqual(await instance.rateForCurrency(sUSD), '1'); - assert.etherEqual(await instance.rateForCurrency(SNX), '0.2'); - - // Ensure that when the rate isn't found, 0 is returned as the exchange rate. - assert.etherEqual(await instance.rateForCurrency(toBytes32('OTHER')), '0'); - - const lastUpdatedTimeSUSD = await instance.lastRateUpdateTimes.call(sUSD); - assert.isAtLeast(lastUpdatedTimeSUSD.toNumber(), initialTime); - - const lastUpdatedTimeOTHER = await instance.lastRateUpdateTimes.call(toBytes32('OTHER')); - assert.equal(lastUpdatedTimeOTHER.toNumber(), 0); - - const lastUpdatedTimeSNX = await instance.lastRateUpdateTimes.call(SNX); - assert.isAtLeast(lastUpdatedTimeSNX.toNumber(), initialTime); - - const sUSDRate = await instance.rateForCurrency(sUSD); - assert.bnEqual(sUSDRate, toUnit('1')); - }); - - it('two different currencies in same array should mean that the second one overrides', async () => { - const creationTime = await currentTime(); - const firstAmount = '4.33'; - const secondAmount = firstAmount + 10; - const instance = await setupContract({ - accounts, - contract, - args: [ - owner, - oracle, - resolver.address, - [toBytes32('CARTER'), toBytes32('CARTOON')], - [web3.utils.toWei(firstAmount, 'ether'), web3.utils.toWei(secondAmount, 'ether')], - ], - }); - - assert.etherEqual(await instance.rateForCurrency(toBytes32('CARTER')), firstAmount); - assert.etherEqual(await instance.rateForCurrency(toBytes32('CARTOON')), secondAmount); - - const lastUpdatedTime = await instance.lastRateUpdateTimes.call(toBytes32('CARTER')); - assert.isAtLeast(lastUpdatedTime.toNumber(), creationTime); - }); - - it('should revert when number of currency keys > new rates length on create', async () => { - await assert.revert( - setupContract({ - accounts, - contract, - args: [ - owner, - oracle, - resolver.address, - [SNX, toBytes32('GOLD')], - [web3.utils.toWei('0.2', 'ether')], - ], - }), - 'Currency key length and rate length must match' - ); - }); - - it('should limit to 32 bytes if currency key > 32 bytes on create', async () => { - const creationTime = await currentTime(); - const amount = '4.33'; - const instance = await setupContract({ - accounts, - contract, - args: [ - owner, - oracle, - resolver.address, - [toBytes32('ABCDEFGHIJKLMNOPQRSTUVXYZ1234567')], - [web3.utils.toWei(amount, 'ether')], - ], - }); - - assert.etherEqual( - await instance.rateForCurrency(toBytes32('ABCDEFGHIJKLMNOPQRSTUVXYZ1234567')), - amount - ); - assert.etherNotEqual( - await instance.rateForCurrency(toBytes32('ABCDEFGHIJKLMNOPQRSTUVXYZ123456')), - amount - ); - - const lastUpdatedTime = await instance.lastRateUpdateTimes.call( - toBytes32('ABCDEFGHIJKLMNOPQRSTUVXYZ1234567') - ); - assert.isAtLeast(lastUpdatedTime.toNumber(), creationTime); - }); - - it("shouldn't be able to set exchange rate to 0 on create", async () => { - await assert.revert( - setupContract({ - accounts, - contract, - args: [owner, oracle, resolver.address, [SNX], ['0']], - }), - 'Zero is not a valid rate, please call deleteRate instead' - ); - }); - - it('should be able to handle lots of currencies on creation', async () => { - const creationTime = await currentTime(); - const numberOfCurrencies = 80; - const { currencyKeys, rates } = createRandomKeysAndRates(numberOfCurrencies); - - const instance = await setupContract({ - accounts, - contract, - args: [owner, oracle, resolver.address, currencyKeys, rates], - }); - - for (let i = 0; i < currencyKeys.length; i++) { - assert.bnEqual(await instance.rateForCurrency(currencyKeys[i]), rates[i]); - const lastUpdatedTime = await instance.lastRateUpdateTimes.call(currencyKeys[i]); - assert.isAtLeast(lastUpdatedTime.toNumber(), creationTime); - } - }); - }); - }; - - // Oracle rates - - const itUpdatesRates = () => { - describe('updateRates()', () => { - it('should be able to update rates of only one currency without affecting other rates', async () => { - await fastForward(1); - - await instance.updateRates( - [toBytes32('lABC'), toBytes32('lDEF'), toBytes32('lGHI')], - [ - web3.utils.toWei('1.3', 'ether'), - web3.utils.toWei('2.4', 'ether'), - web3.utils.toWei('3.5', 'ether'), - ], - timeSent, - { from: oracle } - ); - - await fastForward(10); - const updatedTime = timeSent + 10; - - const updatedRate = '64.33'; - await instance.updateRates( - [toBytes32('lABC')], - [web3.utils.toWei(updatedRate, 'ether')], - updatedTime, - { from: oracle } - ); - - const updatedTimelDEF = await instance.lastRateUpdateTimes.call(toBytes32('lDEF')); - const updatedTimelGHI = await instance.lastRateUpdateTimes.call(toBytes32('lGHI')); - - assert.etherEqual(await instance.rateForCurrency(toBytes32('lABC')), updatedRate); - assert.etherEqual(await instance.rateForCurrency(toBytes32('lDEF')), '2.4'); - assert.etherEqual(await instance.rateForCurrency(toBytes32('lGHI')), '3.5'); - - const lastUpdatedTimeLABC = await instance.lastRateUpdateTimes.call(toBytes32('lABC')); - assert.equal(lastUpdatedTimeLABC.toNumber(), updatedTime); - const lastUpdatedTimeLDEF = await instance.lastRateUpdateTimes.call(toBytes32('lDEF')); - assert.equal(lastUpdatedTimeLDEF.toNumber(), updatedTimelDEF.toNumber()); - const lastUpdatedTimeLGHI = await instance.lastRateUpdateTimes.call(toBytes32('lGHI')); - assert.equal(lastUpdatedTimeLGHI.toNumber(), updatedTimelGHI.toNumber()); - }); - - it('should be able to update rates of all currencies', async () => { - await fastForward(1); - - await instance.updateRates( - [toBytes32('lABC'), toBytes32('lDEF'), toBytes32('lGHI')], - [ - web3.utils.toWei('1.3', 'ether'), - web3.utils.toWei('2.4', 'ether'), - web3.utils.toWei('3.5', 'ether'), - ], - timeSent, - { from: oracle } - ); - - await fastForward(5); - const updatedTime = timeSent + 5; - - const updatedRate1 = '64.33'; - const updatedRate2 = '2.54'; - const updatedRate3 = '10.99'; - await instance.updateRates( - [toBytes32('lABC'), toBytes32('lDEF'), toBytes32('lGHI')], - [ - web3.utils.toWei(updatedRate1, 'ether'), - web3.utils.toWei(updatedRate2, 'ether'), - web3.utils.toWei(updatedRate3, 'ether'), - ], - updatedTime, - { from: oracle } - ); - - assert.etherEqual(await instance.rateForCurrency(toBytes32('lABC')), updatedRate1); - assert.etherEqual(await instance.rateForCurrency(toBytes32('lDEF')), updatedRate2); - assert.etherEqual(await instance.rateForCurrency(toBytes32('lGHI')), updatedRate3); - - const lastUpdatedTimeLABC = await instance.lastRateUpdateTimes.call(toBytes32('lABC')); - assert.equal(lastUpdatedTimeLABC.toNumber(), updatedTime); - const lastUpdatedTimeLDEF = await instance.lastRateUpdateTimes.call(toBytes32('lDEF')); - assert.equal(lastUpdatedTimeLDEF.toNumber(), updatedTime); - const lastUpdatedTimeLGHI = await instance.lastRateUpdateTimes.call(toBytes32('lGHI')); - assert.equal(lastUpdatedTimeLGHI.toNumber(), updatedTime); - }); - - it('should revert when trying to set sUSD price', async () => { - await fastForward(1); - - await assert.revert( - instance.updateRates([sUSD], [web3.utils.toWei('1.0', 'ether')], timeSent, { - from: oracle, - }), - "Rate of sUSD cannot be updated, it's always UNIT" - ); - }); - - it('should emit RatesUpdated event when rate updated', async () => { - const rates = [ - web3.utils.toWei('1.3', 'ether'), - web3.utils.toWei('2.4', 'ether'), - web3.utils.toWei('3.5', 'ether'), - ]; - - const keys = ['lABC', 'lDEF', 'lGHI']; - const currencyKeys = keys.map(toBytes32); - const txn = await instance.updateRates(currencyKeys, rates, await currentTime(), { - from: oracle, - }); - - assert.eventEqual(txn, 'RatesUpdated', { - currencyKeys, - newRates: rates, - }); - }); - - it('should be able to handle lots of currency updates', async () => { - const numberOfCurrencies = 150; - const { currencyKeys, rates } = createRandomKeysAndRates(numberOfCurrencies); - - const updatedTime = await currentTime(); - await instance.updateRates(currencyKeys, rates, updatedTime, { from: oracle }); - - for (let i = 0; i < currencyKeys.length; i++) { - assert.equal(await instance.rateForCurrency(currencyKeys[i]), rates[i]); - const lastUpdatedTime = await instance.lastRateUpdateTimes.call(currencyKeys[i]); - assert.equal(lastUpdatedTime.toNumber(), updatedTime); - } - }); - - it('should revert when currency keys length != new rates length on update', async () => { - await assert.revert( - instance.updateRates( - [sUSD, SNX, toBytes32('GOLD')], - [web3.utils.toWei('1', 'ether'), web3.utils.toWei('0.2', 'ether')], - await currentTime(), - { from: oracle } - ), - 'Currency key array length must match rates array length' - ); - }); - - it('should not be able to set exchange rate to 0 on update', async () => { - await assert.revert( - instance.updateRates( - [toBytes32('ZERO')], - [web3.utils.toWei('0', 'ether')], - await currentTime(), - { from: oracle } - ), - 'Zero is not a valid rate, please call deleteRate instead' - ); - }); - - it('only oracle can update exchange rates', async () => { - await onlyGivenAddressCanInvoke({ - fnc: instance.updateRates, - args: [ - [toBytes32('GOLD'), toBytes32('FOOL')], - [web3.utils.toWei('10', 'ether'), web3.utils.toWei('0.9', 'ether')], - timeSent, - ], - address: oracle, - accounts, - skipPassCheck: true, - reason: 'Only the oracle can perform this action', - }); - - assert.etherNotEqual(await instance.rateForCurrency(toBytes32('GOLD')), '10'); - assert.etherNotEqual(await instance.rateForCurrency(toBytes32('FOOL')), '0.9'); - - const updatedTime = await currentTime(); - - await instance.updateRates( - [toBytes32('GOLD'), toBytes32('FOOL')], - [web3.utils.toWei('10', 'ether'), web3.utils.toWei('0.9', 'ether')], - updatedTime, - { from: oracle } - ); - assert.etherEqual(await instance.rateForCurrency(toBytes32('GOLD')), '10'); - assert.etherEqual(await instance.rateForCurrency(toBytes32('FOOL')), '0.9'); - - const lastUpdatedTimeGOLD = await instance.lastRateUpdateTimes.call(toBytes32('GOLD')); - assert.equal(lastUpdatedTimeGOLD.toNumber(), updatedTime); - const lastUpdatedTimeFOOL = await instance.lastRateUpdateTimes.call(toBytes32('FOOL')); - assert.equal(lastUpdatedTimeFOOL.toNumber(), updatedTime); - }); - - it('should not be able to update rates if they are too far in the future', async () => { - const timeTooFarInFuture = (await currentTime()) + 10 * 61; - await assert.revert( - instance.updateRates( - [toBytes32('GOLD')], - [web3.utils.toWei('1', 'ether')], - timeTooFarInFuture, - { from: oracle } - ), - 'Time is too far into the future' - ); - }); - }); - }; - - const itSetsOracle = () => { - describe('setOracle()', () => { - it("only the owner should be able to change the oracle's address", async () => { - await onlyGivenAddressCanInvoke({ - fnc: instance.setOracle, - args: [oracle], - address: owner, - accounts, - skipPassCheck: true, - }); - - await instance.setOracle(accountOne, { from: owner }); - - assert.equal(await instance.oracle.call(), accountOne); - assert.notEqual(await instance.oracle.call(), oracle); - }); - - it('should emit event on successful oracle address update', async () => { - // Ensure oracle is set to oracle address originally - await instance.setOracle(oracle, { from: owner }); - assert.equal(await instance.oracle.call(), oracle); - - const txn = await instance.setOracle(accountOne, { from: owner }); - assert.eventEqual(txn, 'OracleUpdated', { - newOracle: accountOne, - }); - }); - }); - }; - - const itDeletesRates = () => { - describe('deleteRate()', () => { - it('should be able to remove specific rate', async () => { - const foolsRate = '0.002'; - const encodedRateGOLD = toBytes32('GOLD'); - - await instance.updateRates( - [encodedRateGOLD, toBytes32('FOOL')], - [web3.utils.toWei('10.123', 'ether'), web3.utils.toWei(foolsRate, 'ether')], - timeSent, - { from: oracle } - ); - - const beforeRate = await instance.rateForCurrency(encodedRateGOLD); - const beforeRateUpdatedTime = await instance.lastRateUpdateTimes.call(encodedRateGOLD); - - await instance.deleteRate(encodedRateGOLD, { from: oracle }); - - const afterRate = await instance.rateForCurrency(encodedRateGOLD); - const afterRateUpdatedTime = await instance.lastRateUpdateTimes.call(encodedRateGOLD); - assert.notEqual(afterRate, beforeRate); - assert.equal(afterRate, '0'); - assert.notEqual(afterRateUpdatedTime, beforeRateUpdatedTime); - assert.equal(afterRateUpdatedTime, '0'); - - // Other rates are unaffected - assert.etherEqual(await instance.rateForCurrency(toBytes32('FOOL')), foolsRate); - }); - - it('only oracle can delete a rate', async () => { - // Assume that the contract is already set up with a valid oracle account called 'oracle' - - const encodedRateName = toBytes32('COOL'); - await instance.updateRates( - [encodedRateName], - [web3.utils.toWei('10.123', 'ether')], - await currentTime(), - { from: oracle } - ); - - await onlyGivenAddressCanInvoke({ - fnc: instance.deleteRate, - args: [encodedRateName], - accounts, - address: oracle, - reason: 'Only the oracle can perform this action', - }); - }); - - it("deleting rate that doesn't exist causes revert", async () => { - // This key shouldn't exist but let's do the best we can to ensure that it doesn't - const encodedCurrencyKey = toBytes32('7NEQ'); - const currentRate = await instance.rateForCurrency(encodedCurrencyKey); - if (currentRate > 0) { - await instance.deleteRate(encodedCurrencyKey, { from: oracle }); - } - - // Ensure rate deletion attempt results in revert - await assert.revert( - instance.deleteRate(encodedCurrencyKey, { from: oracle }), - 'Rate is zero' - ); - assert.etherEqual(await instance.rateForCurrency(encodedCurrencyKey), '0'); }); - it('should emit RateDeleted event when rate deleted', async () => { - const updatedTime = await currentTime(); - const rate = 'GOLD'; - const encodedRate = toBytes32(rate); - await instance.updateRates( - [encodedRate], - [web3.utils.toWei('10.123', 'ether')], - updatedTime, - { - from: oracle, - } - ); - - const txn = await instance.deleteRate(encodedRate, { from: oracle }); - assert.eventEqual(txn, 'RateDeleted', { currencyKey: encodedRate }); - }); - }); - }; - - const itReturnsRates = () => { - describe('getting rates', () => { - it('should be able to get exchange rate with key', async () => { - const updatedTime = await currentTime(); - const encodedRate = toBytes32('GOLD'); - const rateValueEncodedStr = web3.utils.toWei('10.123', 'ether'); - await instance.updateRates([encodedRate], [rateValueEncodedStr], updatedTime, { - from: oracle, - }); - - const rate = await instance.rateForCurrency(encodedRate); - assert.equal(rate, rateValueEncodedStr); - }); - - it('all users should be able to get exchange rate with key', async () => { - const updatedTime = await currentTime(); - const encodedRate = toBytes32('FETC'); - const rateValueEncodedStr = web3.utils.toWei('910.6661293879', 'ether'); - await instance.updateRates([encodedRate], [rateValueEncodedStr], updatedTime, { - from: oracle, - }); - - await instance.rateForCurrency(encodedRate, { from: accountOne }); - await instance.rateForCurrency(encodedRate, { from: accountTwo }); - await instance.rateForCurrency(encodedRate, { from: oracle }); - await instance.rateForCurrency(encodedRate, { from: owner }); - await instance.rateForCurrency(encodedRate, { from: deployerAccount }); - }); - - it('Fetching non-existent rate returns 0', async () => { - const encodedRateKey = toBytes32('GOLD'); - const currentRate = await instance.rateForCurrency(encodedRateKey); - if (currentRate > 0) { - await instance.deleteRate(encodedRateKey, { from: oracle }); - } - - const rate = await instance.rateForCurrency(encodedRateKey); - assert.equal(rate.toString(), '0'); - }); - - it('should be able to get the latest exchange rate and updated time', async () => { - const updatedTime = await currentTime(); - const encodedRate = toBytes32('GOLD'); - const rateValueEncodedStr = web3.utils.toWei('10.123', 'ether'); - await instance.updateRates([encodedRate], [rateValueEncodedStr], updatedTime, { - from: oracle, - }); - - const rateAndTime = await instance.rateAndUpdatedTime(encodedRate); - assert.equal(rateAndTime.rate, rateValueEncodedStr); - assert.bnEqual(rateAndTime.time, updatedTime); + it('returns correct values for sUSD after deployment ', async () => { + assert.bnEqual(await instance.rateForCurrency(sUSD), toUnit('1')); + assert.equal(await instance.lastRateUpdateTimes(sUSD), 0); }); }); }; @@ -621,62 +104,18 @@ contract('Exchange Rates', async accounts => { assert.equal(rateIsStale, false); }); - it('check if a single rate is stale', async () => { - // Set up rates for test - await systemSettings.setRateStalePeriod(30, { from: owner }); - const updatedTime = await currentTime(); - await instance.updateRates( - [toBytes32('ABC')], - [web3.utils.toWei('2', 'ether')], - updatedTime, - { - from: oracle, - } - ); - await fastForward(31); - - const rateIsStale = await instance.rateIsStale(toBytes32('ABC')); - assert.equal(rateIsStale, true); - }); - - it('check if a single rate is not stale', async () => { - // Set up rates for test - await systemSettings.setRateStalePeriod(30, { from: owner }); - const updatedTime = await currentTime(); - await instance.updateRates( - [toBytes32('ABC')], - [web3.utils.toWei('2', 'ether')], - updatedTime, - { - from: oracle, - } - ); - await fastForward(28); - - const rateIsStale = await instance.rateIsStale(toBytes32('ABC')); - assert.equal(rateIsStale, false); - }); - - it('ensure rate is considered stale if not set', async () => { + it('ensure stale if not set', async () => { // Set up rates for test await systemSettings.setRateStalePeriod(30, { from: owner }); - const encodedRateKey = toBytes32('GOLD'); - const currentRate = await instance.rateForCurrency(encodedRateKey); - if (currentRate > 0) { - await instance.deleteRate(encodedRateKey, { from: oracle }); - } - - const rateIsStale = await instance.rateIsStale(encodedRateKey); - assert.equal(rateIsStale, true); + assert.equal(await instance.rateIsStale(toBytes32('GOLD')), true); }); it('make sure anyone can check if rate is stale', async () => { - const rateKey = toBytes32('ABC'); - await instance.rateIsStale(rateKey, { from: oracle }); - await instance.rateIsStale(rateKey, { from: owner }); - await instance.rateIsStale(rateKey, { from: deployerAccount }); - await instance.rateIsStale(rateKey, { from: accountOne }); - await instance.rateIsStale(rateKey, { from: accountTwo }); + await instance.rateIsStale(sUSD, { from: oracle }); + await instance.rateIsStale(sUSD, { from: owner }); + await instance.rateIsStale(sUSD, { from: deployerAccount }); + await instance.rateIsStale(sUSD, { from: accountOne }); + await instance.rateIsStale(sUSD, { from: accountTwo }); }); }); }; @@ -684,29 +123,18 @@ contract('Exchange Rates', async accounts => { const itCalculatesInvalidRates = () => { describe('anyRateIsInvalid()', () => { describe('stale scenarios', () => { - it('should never allow sUSD to go stale via anyRateIsInvalid', async () => { - const keysArray = [SNX, toBytes32('GOLD')]; - - await instance.updateRates( - keysArray, - [web3.utils.toWei('0.1', 'ether'), web3.utils.toWei('0.2', 'ether')], - await currentTime(), - { from: oracle } - ); - assert.equal(await instance.anyRateIsInvalid(keysArray), false); + it('anyRateIsInvalid conforms to rateStalePeriod', async () => { + await setupAggregators([SNX, GOLD]); - await fastForward(await instance.rateStalePeriod()); + await updateRates([SNX, GOLD], [toUnit(0.1), toUnit(0.2)]); - await instance.updateRates( - [SNX, toBytes32('GOLD')], - [web3.utils.toWei('0.1', 'ether'), web3.utils.toWei('0.2', 'ether')], - await currentTime(), - { from: oracle } - ); + assert.equal(await instance.anyRateIsInvalid([SNX, GOLD]), false); - // Even though sUSD hasn't been updated since the stale rate period has expired, - // we expect that sUSD remains "not stale" - assert.equal(await instance.anyRateIsInvalid(keysArray), false); + await fastForward(await instance.rateStalePeriod()); + assert.equal(await instance.anyRateIsInvalid([SNX, GOLD]), true); + + await updateRates([SNX, GOLD], [toUnit(0.1), toUnit(0.2)]); + assert.equal(await instance.anyRateIsInvalid([SNX, GOLD]), false); }); it('should be able to confirm no rates are stale from a subset', async () => { @@ -742,20 +170,19 @@ contract('Exchange Rates', async accounts => { web3.utils.toWei('10', 'ether'), web3.utils.toWei('11', 'ether'), ]; + + await setupAggregators([...encodedRateKeys1, ...encodedRateKeys2, ...encodedRateKeys3]); + const updatedTime1 = await currentTime(); - await instance.updateRates(encodedRateKeys1, encodedRateValues1, updatedTime1, { - from: oracle, - }); + await updateRates(encodedRateKeys1, encodedRateValues1, updatedTime1); + await fastForward(5); const updatedTime2 = await currentTime(); - await instance.updateRates(encodedRateKeys2, encodedRateValues2, updatedTime2, { - from: oracle, - }); + await updateRates(encodedRateKeys2, encodedRateValues2, updatedTime2); + await fastForward(5); const updatedTime3 = await currentTime(); - await instance.updateRates(encodedRateKeys3, encodedRateValues3, updatedTime3, { - from: oracle, - }); + await updateRates(encodedRateKeys3, encodedRateValues3, updatedTime3); await fastForward(12); const rateIsInvalid = await instance.anyRateIsInvalid([ @@ -789,21 +216,18 @@ contract('Exchange Rates', async accounts => { web3.utils.toWei('8', 'ether'), ]; + await setupAggregators([...encodedRateKeys1, ...encodedRateKeys2, ...encodedRateKeys3]); + const updatedTime2 = await currentTime(); - await instance.updateRates(encodedRateKeys2, encodedRateValues2, updatedTime2, { - from: oracle, - }); + await updateRates(encodedRateKeys2, encodedRateValues2, updatedTime2); await fastForward(20); const updatedTime1 = await currentTime(); - await instance.updateRates(encodedRateKeys1, encodedRateValues1, updatedTime1, { - from: oracle, - }); + await updateRates(encodedRateKeys1, encodedRateValues1, updatedTime1); await fastForward(15); + const updatedTime3 = await currentTime(); - await instance.updateRates(encodedRateKeys3, encodedRateValues3, updatedTime3, { - from: oracle, - }); + await updateRates(encodedRateKeys3, encodedRateValues3, updatedTime3); await fastForward(6); const rateIsInvalid = await instance.anyRateIsInvalid([ @@ -816,23 +240,18 @@ contract('Exchange Rates', async accounts => { it('should be able to confirm a single rate (from a set of 1) is stale', async () => { // Set up rates for test await systemSettings.setRateStalePeriod(40, { from: owner }); - const updatedTime = await currentTime(); - await instance.updateRates( - [toBytes32('ABC')], - [web3.utils.toWei('2', 'ether')], - updatedTime, - { - from: oracle, - } - ); + const key = toBytes32('ABC'); + await setupAggregators([key]); + await updateRates([key], [web3.utils.toWei('2', 'ether')]); await fastForward(41); - const rateIsInvalid = await instance.anyRateIsInvalid([toBytes32('ABC')]); + const rateIsInvalid = await instance.anyRateIsInvalid([key]); assert.equal(rateIsInvalid, true); }); it('make sure anyone can check if any rates are stale', async () => { const rateKey = toBytes32('ABC'); + await setupAggregators([rateKey]); await instance.anyRateIsInvalid([rateKey], { from: oracle }); await instance.anyRateIsInvalid([rateKey], { from: owner }); await instance.anyRateIsInvalid([rateKey], { from: deployerAccount }); @@ -856,14 +275,13 @@ contract('Exchange Rates', async accounts => { web3.utils.toWei('4', 'ether'), ]; - const updatedTime1 = await currentTime(); - await instance.updateRates(encodedRateKeys1, encodedRateValues1, updatedTime1, { - from: oracle, - }); - const rateIsInvalid = await instance.anyRateIsInvalid([ - ...encodedRateKeys1, - toBytes32('RST'), - ]); + const staleKey = toBytes32('RST'); + const allKeys = [...encodedRateKeys1, staleKey]; + + await setupAggregators(allKeys); + await updateRates(encodedRateKeys1, encodedRateValues1); + + const rateIsInvalid = await instance.anyRateIsInvalid(allKeys); assert.equal(rateIsInvalid, true); }); }); @@ -875,20 +293,13 @@ contract('Exchange Rates', async accounts => { from: owner, }); }); - describe('when a regular and aggregated synth have rates', () => { + describe('when aggregated synth has rates', () => { beforeEach(async () => { const timestamp = await currentTime(); - await instance.updateRates([toBytes32('sGOLD')], [web3.utils.toWei('1')], timestamp, { - from: oracle, - }); await aggregatorJPY.setLatestAnswer(convertToDecimals(100, 8), timestamp); }); - it('then rateIsInvalid for both is false', async () => { - const rateIsInvalid = await instance.anyRateIsInvalid([ - toBytes32('sGOLD'), - sJPY, - sUSD, - ]); + it('then rateIsInvalid is false', async () => { + const rateIsInvalid = await instance.anyRateIsInvalid([sJPY, sUSD]); assert.equal(rateIsInvalid, false); }); @@ -902,12 +313,8 @@ contract('Exchange Rates', async accounts => { }); }); - it('then rateIsInvalid for both is still false', async () => { - const rateIsInvalid = await instance.anyRateIsInvalid([ - toBytes32('sGOLD'), - sJPY, - sUSD, - ]); + it('then rateIsInvalid is still false', async () => { + const rateIsInvalid = await instance.anyRateIsInvalid([sJPY, sUSD]); assert.equal(rateIsInvalid, false); }); @@ -915,12 +322,8 @@ contract('Exchange Rates', async accounts => { beforeEach(async () => { await mockFlagsInterface.flagAggregator(aggregatorJPY.address); }); - it('then rateIsInvalid for both is true', async () => { - const rateIsInvalid = await instance.anyRateIsInvalid([ - toBytes32('sGOLD'), - sJPY, - sUSD, - ]); + it('then rateIsInvalid is true', async () => { + const rateIsInvalid = await instance.anyRateIsInvalid([sJPY, sUSD]); assert.equal(rateIsInvalid, true); }); }); @@ -937,21 +340,13 @@ contract('Exchange Rates', async accounts => { const abc = toBytes32('lABC'); const timeSent = await currentTime(); const listOfKeys = [abc, toBytes32('lDEF'), toBytes32('lGHI')]; - await instance.updateRates( - listOfKeys.slice(0, 2), - [web3.utils.toWei('1.3', 'ether'), web3.utils.toWei('2.4', 'ether')], - timeSent, - { from: oracle } - ); + await setupAggregators(listOfKeys); + + await updateRates(listOfKeys.slice(0, 2), [toUnit('1.3'), toUnit('2.4')], timeSent); await fastForward(100); const newTimeSent = await currentTime(); - await instance.updateRates( - listOfKeys.slice(2), - [web3.utils.toWei('3.5', 'ether')], - newTimeSent, - { from: oracle } - ); + await updateRates(listOfKeys.slice(2), [toUnit('3.5')], newTimeSent); const lastUpdateTimes = await instance.lastRateUpdateTimesForCurrencies(listOfKeys); assert.notEqual(timeSent, newTimeSent); @@ -965,18 +360,14 @@ contract('Exchange Rates', async accounts => { const abc = toBytes32('lABC'); const def = toBytes32('lDEF'); const ghi = toBytes32('lGHI'); + await setupAggregators([abc, def, ghi]); + const timeSent = await currentTime(); - await instance.updateRates( - [abc, def], - [web3.utils.toWei('1.3', 'ether'), web3.utils.toWei('2.4', 'ether')], - timeSent, - { from: oracle } - ); + await updateRates([abc, def], [toUnit('1.3'), toUnit('2.4')], timeSent); + await fastForward(10000); const timeSent2 = await currentTime(); - await instance.updateRates([ghi], [web3.utils.toWei('2.4', 'ether')], timeSent2, { - from: oracle, - }); + await updateRates([ghi], [toUnit('2.4')], timeSent2); const [firstTS, secondTS] = await Promise.all([ instance.lastRateUpdateTimes(abc), @@ -990,21 +381,14 @@ contract('Exchange Rates', async accounts => { const itCalculatesEffectiveValue = () => { describe('effectiveValue() and effectiveValueAndRates()', () => { - let timestamp; - beforeEach(async () => { - timestamp = await currentTime(); - }); - describe('when a price is sent to the oracle', () => { beforeEach(async () => { // Send a price update to guarantee we're not depending on values from outside this test. - await instance.updateRates( - ['sAUD', 'sEUR', 'SNX'].map(toBytes32), - ['0.5', '1.25', '0.1'].map(toUnit), - timestamp, - { from: oracle } - ); + const keys = [sAUD, sEUR, SNX]; + await setupAggregators(keys); + await updateRates(keys, ['0.5', '1.25', '0.1'].map(toUnit)); }); + it('should correctly calculate an exchange rate in effectiveValue()', async () => { // 1 sUSD should be worth 2 sAUD. assert.bnEqual(await instance.effectiveValue(sUSD, toUnit('1'), sAUD), toUnit('2')); @@ -1020,12 +404,8 @@ contract('Exchange Rates', async accounts => { // Add stale period to the time to ensure we go stale. await fastForward((await instance.rateStalePeriod()) + 1); - timestamp = await currentTime(); - // Update all rates except sUSD. - await instance.updateRates([sEUR, SNX], ['1.25', '0.1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sEUR, SNX], ['1.25', '0.1'].map(toUnit)); const amountOfSynthetixs = toUnit('10'); const amountOfEur = toUnit('0.8'); @@ -1035,11 +415,11 @@ contract('Exchange Rates', async accounts => { }); it('should return 0 when relying on a non-existant dest exchange rate in effectiveValue()', async () => { - assert.equal(await instance.effectiveValue(SNX, toUnit('10'), toBytes32('XYZ')), '0'); + assert.equal(await instance.effectiveValue(SNX, toUnit('10'), toBytes32('XYZ')), 0); }); - it('should return 0 when relying on a non-existing src rate in effectiveValue', async () => { - assert.equal(await instance.effectiveValue(toBytes32('XYZ'), toUnit('10'), SNX), '0'); + it('should revert when relying on a non-existing src rate in effectiveValue', async () => { + assert.equal(await instance.effectiveValue(toBytes32('XYZ'), toUnit('10'), SNX), 0); }); it('effectiveValueAndRates() should return rates as well with sUSD on one side', async () => { @@ -1081,8 +461,6 @@ contract('Exchange Rates', async accounts => { }); }; - // Aggregator rates and flags - const itReadsFromAggregator = () => { describe('when the flags interface is set', () => { beforeEach(async () => { @@ -1411,45 +789,27 @@ contract('Exchange Rates', async accounts => { await assert.invalidOpcode(instance.aggregatorKeys(1)); }); }); - describe('when the ratesAndInvalidForCurrencies is queried', () => { - let response; - beforeEach(async () => { - response = await instance.ratesAndInvalidForCurrencies([sJPY, sXTZ, sUSD]); - }); - - it('then the rates are invalid again', () => { - assert.equal(response[1], true); - }); - - it('and JPY is 0 while the other is fine', () => { - assert.equal(response[0][0], '0'); - assert.bnEqual(response[0][1], toUnit(newRateXTZ.toString())); - }); + it('when the ratesAndInvalidForCurrencies is queried it returns 0', async () => { + assert.deepEqual( + await instance.ratesAndInvalidForCurrencies([sJPY, sXTZ, sUSD]), + [[0, toUnit(newRateXTZ), toUnit(1)], true] + ); }); describe('when rateAndInvalid is queried', () => { - let responseJPY; - let responseXTZ; - let responseUSD; - beforeEach(async () => { - responseJPY = await instance.rateAndInvalid(sJPY); - responseXTZ = await instance.rateAndInvalid(sXTZ); - responseUSD = await instance.rateAndInvalid(sUSD); + it('then JPY returns true', async () => { + assert.deepEqual(await instance.rateAndInvalid(sJPY), [0, true]); }); - it('then the rates are invalid again', () => { - assert.equal(responseJPY[1], true); + it('other rates are fine', async () => { + const responseXTZ = await instance.rateAndInvalid(sXTZ); + const responseUSD = await instance.rateAndInvalid(sUSD); + assert.equal(responseXTZ[1], false); assert.equal(responseUSD[1], false); - }); - - it('and JPY is 0 while the other is fine', () => { - assert.bnEqual(responseJPY[0], toUnit('0')); assert.bnEqual(responseXTZ[0], toUnit(newRateXTZ.toString())); assert.bnEqual(responseUSD[0], toUnit('1')); }); }); - - describe('when sJPY has a non-aggregated rate', () => {}); }); }); }); @@ -1512,293 +872,6 @@ contract('Exchange Rates', async accounts => { }); }); - describe('when a price already exists for sJPY', () => { - const oldPrice = toUnit(100); - let timeOldSent; - beforeEach(async () => { - timeOldSent = await currentTime(); - - await instance.updateRates([sJPY], [oldPrice], timeOldSent, { - from: oracle, - }); - }); - describe('when the ratesAndInvalidForCurrencies is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.ratesAndInvalidForCurrencies([sJPY, sUSD]); - }); - - it('then the rates are NOT invalid', () => { - assert.equal(response[1], false); - }); - - it('and equal to the value', () => { - assert.bnEqual(response[0][0], oldPrice); - }); - }); - describe('when rateAndInvalid is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.rateAndInvalid(sJPY); - }); - - it('then the rate is NOT invalid', () => { - assert.equal(response[1], false); - }); - - it('and equal to the value', () => { - assert.bnEqual(response[0], oldPrice); - }); - }); - - describe('when the price is inspected for sJPY', () => { - it('then the price is returned as expected', async () => { - const result = await instance.rateForCurrency(sJPY, { - from: accountOne, - }); - assert.equal(result.toString(), oldPrice); - }); - it('then the timestamp is returned as expected', async () => { - const result = await instance.lastRateUpdateTimes(sJPY, { - from: accountOne, - }); - assert.equal(result.toNumber(), timeOldSent); - }); - }); - - describe('when sJPY added as an aggregator (replacing existing)', () => { - beforeEach(async () => { - await instance.addAggregator(sJPY, aggregatorJPY.address, { - from: owner, - }); - }); - describe('when the price is fetched for sJPY', () => { - it('0 is returned', async () => { - const result = await instance.rateForCurrency(sJPY, { - from: accountOne, - }); - assert.equal(result.toNumber(), 0); - }); - }); - describe('when the timestamp is fetched for sJPY', () => { - it('0 is returned', async () => { - const result = await instance.lastRateUpdateTimes(sJPY, { - from: accountOne, - }); - assert.equal(result.toNumber(), 0); - }); - }); - describe('when the ratesAndInvalidForCurrencies is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.ratesAndInvalidForCurrencies([sJPY]); - }); - - it('then the rates are invalid', () => { - assert.equal(response[1], true); - }); - - it('with no value', () => { - assert.bnEqual(response[0][0], '0'); - }); - }); - describe('when the rateAndInvalid is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.rateAndInvalid(sJPY); - }); - - it('then the rate is invalid', () => { - assert.equal(response[1], true); - }); - - it('with no value', () => { - assert.bnEqual(response[0], '0'); - }); - }); - - describe('when the aggregator price is set to set a specific number (with support for 8 decimals)', () => { - const newRate = 9.55; - let timestamp; - beforeEach(async () => { - await fastForward(50); - timestamp = await currentTime(); - // Need to set twice in order to increase the roundId in aggregator - // to be greater than the one in the cache - await aggregatorJPY.setLatestAnswer(convertToDecimals(newRate, 8), timestamp); - await aggregatorJPY.setLatestAnswer(convertToDecimals(newRate, 8), timestamp); - }); - - describe('when the price is fetched for sJPY', () => { - it('the new aggregator rate is returned instead of the old price', async () => { - const result = await instance.rateForCurrency(sJPY, { - from: accountOne, - }); - assert.bnEqual(result, toUnit(newRate.toString())); - }); - it('and the timestamp is the new one', async () => { - const result = await instance.lastRateUpdateTimes(sJPY, { - from: accountOne, - }); - assert.bnEqual(result.toNumber(), timestamp); - }); - }); - - describe('when the ratesAndInvalidForCurrencies is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.ratesAndInvalidForCurrencies([sJPY, sUSD]); - }); - - it('then the rates are NOT invalid', () => { - assert.equal(response[1], false); - }); - - it('and equal to the value', () => { - assert.bnEqual(response[0][0], toUnit(newRate.toString())); - }); - }); - - describe('when rateAndInvalid is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.rateAndInvalid(sJPY); - }); - - it('then the rates are NOT invalid', () => { - assert.equal(response[1], false); - }); - - it('and equal to the value', () => { - assert.bnEqual(response[0], toUnit(newRate.toString())); - }); - }); - - describe('when the aggregator is removed for sJPY', () => { - beforeEach(async () => { - await instance.removeAggregator(sJPY, { - from: owner, - }); - }); - describe('when a user queries the first entry in aggregatorKeys', () => { - it('then they are empty', async () => { - await assert.invalidOpcode(instance.aggregatorKeys(0)); - }); - }); - describe('when the price is inspected for sJPY', () => { - it('then the old price is returned', async () => { - const result = await instance.rateForCurrency(sJPY, { - from: accountOne, - }); - assert.equal(result.toString(), oldPrice); - }); - it('and the timestamp is returned as expected', async () => { - const result = await instance.lastRateUpdateTimes(sJPY, { - from: accountOne, - }); - assert.equal(result.toNumber(), timeOldSent); - }); - }); - describe('when the ratesAndInvalidForCurrencies is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.ratesAndInvalidForCurrencies([sJPY, sUSD]); - }); - - it('then the rates are NOT invalid', () => { - assert.equal(response[1], false); - }); - - it('and equal to the old value', () => { - assert.bnEqual(response[0][0], oldPrice); - }); - }); - - describe('when the rateAndInvalid is queried with sJPY', () => { - let response; - beforeEach(async () => { - response = await instance.rateAndInvalid(sJPY); - }); - - it('then the rates are NOT invalid', () => { - assert.equal(response[1], false); - }); - - it('and equal to the old value', () => { - assert.bnEqual(response[0], oldPrice); - }); - }); - }); - }); - }); - - describe('when sXTZ added as an aggregator', () => { - beforeEach(async () => { - await instance.addAggregator(sXTZ, aggregatorXTZ.address, { - from: owner, - }); - }); - describe('when the ratesAndInvalidForCurrencies is queried with sJPY and sXTZ', () => { - let response; - beforeEach(async () => { - response = await instance.ratesAndInvalidForCurrencies([sJPY, sXTZ, sUSD]); - }); - - it('then the rates are invalid', () => { - assert.equal(response[1], true); - }); - - it('with sXTZ having no value', () => { - assert.bnEqual(response[0][0], oldPrice); - assert.bnEqual(response[0][1], '0'); - }); - }); - describe('when the rateAndInvalid is queried with sJPY and sXTZ', () => { - let responseJPY; - let responseXTZ; - beforeEach(async () => { - responseJPY = await instance.rateAndInvalid(sJPY); - responseXTZ = await instance.rateAndInvalid(sXTZ); - }); - - it('then the XTZ rate is invalid', () => { - assert.equal(responseJPY[1], false); - assert.equal(responseXTZ[1], true); - }); - - it('with sXTZ having no value', () => { - assert.bnEqual(responseJPY[0], oldPrice); - assert.bnEqual(responseXTZ[0], '0'); - }); - }); - - describe('when the aggregator price is set to set for sXTZ', () => { - const newRate = 99; - let timestamp; - beforeEach(async () => { - await fastForward(50); - timestamp = await currentTime(); - await aggregatorXTZ.setLatestAnswer(convertToDecimals(newRate, 8), timestamp); - }); - - describe('when the ratesAndInvalidForCurrencies is queried with sJPY and sXTZ', () => { - let response; - beforeEach(async () => { - response = await instance.ratesAndInvalidForCurrencies([sJPY, sXTZ, sUSD]); - }); - - it('then the rates are NOT invalid', () => { - assert.equal(response[1], false); - }); - - it('and equal to the values', () => { - assert.bnEqual(response[0][0], oldPrice); - assert.bnEqual(response[0][1], toUnit(newRate.toString())); - }); - }); - }); - }); - }); describe('warning flags and invalid rates', () => { it('sUSD is never flagged / invalid.', async () => { assert.isFalse(await instance.rateIsFlagged(sUSD)); @@ -1860,24 +933,31 @@ contract('Exchange Rates', async accounts => { }); describe('roundIds for historical rates', () => { - it('getCurrentRoundId() by default is 0 for all synths except sUSD which is 1', async () => { - // Note: rates that were set in the truffle migration will be at 1, so we need to check - // other synths - assert.equal(await instance.getCurrentRoundId(sJPY), '0'); - assert.equal(await instance.getCurrentRoundId(sBNB), '0'); - assert.equal(await instance.getCurrentRoundId(sUSD), '1'); + it('getCurrentRoundId() returns 0 for unknown currencies', async () => { + assert.equal(await instance.getCurrentRoundId(sJPY), 0); + assert.equal(await instance.getCurrentRoundId(sBNB), 0); + }); + + it('getCurrentRoundId() is 0 for currencies with no updates', async () => { + await setupAggregators([sJPY, sBNB]); + assert.equal(await instance.getCurrentRoundId(sJPY), 0); + assert.equal(await instance.getCurrentRoundId(sBNB), 0); + }); + + it('getCurrentRoundId() is 0 for sUSD', async () => { + assert.equal(await instance.getCurrentRoundId(sUSD), 0); }); it('ratesAndUpdatedTimeForCurrencyLastNRounds() shows first entry for sUSD', async () => { - const timeOfsUSDRateSetOnInit = await instance.lastRateUpdateTimes(sUSD); - assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sUSD, '3', '0'), [ + assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sUSD, '3'), [ [toUnit('1'), '0', '0'], - [timeOfsUSDRateSetOnInit, '0', '0'], + [0, 0, 0], ]); }); - it('ratesAndUpdatedTimeForCurrencyLastNRounds() returns 0s for other currency keys', async () => { + it('ratesAndUpdatedTimeForCurrencyLastNRounds() returns 0s for other currencies without updates', async () => { const fiveZeros = new Array(5).fill('0'); - assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sAUD, '5', '0'), [ + await setupAggregators([sJPY]); + assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '5'), [ fiveZeros, fiveZeros, ]); @@ -1898,145 +978,83 @@ contract('Exchange Rates', async accounts => { } }); - describe('and the sBNB rate (non-aggregator) has been set three times directly also', () => { - let timestamp; - - beforeEach(async () => { - for (let i = 0; i < 3; i++) { - timestamp = 10000; - await instance.updateRates([sBNB], [toUnit((1000 + i).toString())], timestamp + i, { - from: oracle, - }); - } - }); - describe('getCurrentRoundId())', () => { - describe('when invoked for an aggregator', () => { - it('getCurrentRound() returns the last entry', async () => { - await assert.equal((await instance.getCurrentRoundId(sJPY)).toString(), '3'); - }); - }); - describe('when invoked for a regular price', () => { - it('getCurrentRound() returns the last entry', async () => { - await assert.equal((await instance.getCurrentRoundId(sBNB)).toString(), '3'); - }); + describe('getCurrentRoundId())', () => { + describe('when invoked for an aggregator', () => { + it('getCurrentRound() returns the last entry', async () => { + assert.equal((await instance.getCurrentRoundId(sJPY)).toString(), '3'); }); }); - describe('rateAndTimestampAtRound()', () => { - it('when invoked for no price, returns no rate and no tme', async () => { + }); + describe('rateAndTimestampAtRound()', () => { + it('when invoked for no price returns 0', async () => { + assert.deepEqual(await instance.rateAndTimestampAtRound(toBytes32('TEST'), '0'), [ + 0, + 0, + ]); + }); + it('when invoked for an aggregator', async () => { + const assertRound = async ({ roundId }) => { const { rate, time } = await instance.rateAndTimestampAtRound( - toBytes32('TEST'), - '0' + sJPY, + roundId.toString() + ); + assert.bnEqual(rate, toUnit((100 + roundId - 1).toString())); + assert.bnEqual(time, toBN(1000 + roundId - 1)); + }; + await assertRound({ roundId: 1 }); + await assertRound({ roundId: 2 }); + await assertRound({ roundId: 3 }); + }); + }); + + describe('ratesAndUpdatedTimeForCurrencyLastNRounds()', () => { + describe('when invoked for a non-existant currency', () => { + it('then it returns zeros', async () => { + const fiveZeros = new Array(5).fill('0'); + assert.deepEqual( + await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sAUD, '5'), + [fiveZeros, fiveZeros] ); - assert.equal(rate, '0'); - assert.equal(time, '0'); - }); - it('when invoked for an aggregator', async () => { - const assertRound = async ({ roundId }) => { - const { rate, time } = await instance.rateAndTimestampAtRound( - sJPY, - roundId.toString() - ); - assert.bnEqual(rate, toUnit((100 + roundId - 1).toString())); - assert.bnEqual(time, toBN(1000 + roundId - 1)); - }; - await assertRound({ roundId: 1 }); - await assertRound({ roundId: 2 }); - await assertRound({ roundId: 3 }); - }); - it('when invoked for a regular price', async () => { - const assertRound = async ({ roundId }) => { - const { rate, time } = await instance.rateAndTimestampAtRound( - sBNB, - roundId.toString() - ); - assert.bnEqual(rate, toUnit((1000 + roundId - 1).toString())); - assert.bnEqual(time, toBN(10000 + roundId - 1)); - }; - await assertRound({ roundId: 1 }); - await assertRound({ roundId: 2 }); - await assertRound({ roundId: 3 }); }); }); - - describe('ratesAndUpdatedTimeForCurrencyLastNRounds()', () => { - describe('when invoked for a non-existant currency', () => { - it('then it returns 0s', async () => { - const fiveZeros = new Array(5).fill('0'); - assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sAUD, '5', '0'), - [fiveZeros, fiveZeros] - ); - }); - }); - describe('when invoked for an aggregated price', () => { - it('then it returns the rates as expected', async () => { - assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '3', '0'), - [ - [toUnit('102'), toUnit('101'), toUnit('100')], - ['1002', '1001', '1000'], - ] - ); - }); - - it('then it returns the rates as expected, even over the edge', async () => { - assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '5', '0'), - [ - [toUnit('102'), toUnit('101'), toUnit('100'), '0', '0'], - ['1002', '1001', '1000', '0', '0'], - ] - ); - }); + describe('when invoked for an aggregated price', () => { + it('then it returns the rates as expected', async () => { + assert.deepEqual( + await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '3'), + [ + [toUnit('102'), toUnit('101'), toUnit('100')], + ['1002', '1001', '1000'], + ] + ); }); - describe('when invoked for a regular price', () => { - it('then it returns the rates as expected', async () => { - assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sBNB, '3', '0'), - [ - [toUnit('1002'), toUnit('1001'), toUnit('1000')], - ['10002', '10001', '10000'], - ] - ); - }); - it('then it returns the rates as expected, even over the edge', async () => { - assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sBNB, '5', '0'), - [ - [toUnit('1002'), toUnit('1001'), toUnit('1000'), '0', '0'], - ['10002', '10001', '10000', '0', '0'], - ] - ); - }); + it('then it returns the rates as expected, even over the edge', async () => { + assert.deepEqual( + await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '5'), + [ + [toUnit('102'), toUnit('101'), toUnit('100'), '0', '0'], + ['1002', '1001', '1000', '0', '0'], + ] + ); }); }); }); }); - describe('and both the aggregator and regular prices have been given three rates, 30seconds apart', () => { + describe('and the aggregator has been given three rates, 30seconds apart', () => { beforeEach(async () => { await aggregatorJPY.setLatestAnswer(convertToDecimals(100, 8), 30); // round 1 for sJPY await aggregatorJPY.setLatestAnswer(convertToDecimals(200, 8), 60); // round 2 for sJPY await aggregatorJPY.setLatestAnswer(convertToDecimals(300, 8), 90); // round 3 for sJPY - - await instance.updateRates([sBNB], [toUnit('1000')], '30', { from: oracle }); // round 1 for sBNB - await instance.updateRates([sBNB], [toUnit('2000')], '60', { from: oracle }); // round 2 for sBNB - await instance.updateRates([sBNB], [toUnit('3000')], '90', { from: oracle }); // round 3 for sBNB }); describe('getLastRoundIdBeforeElapsedSecs()', () => { describe('when getLastRoundIdBeforeElapsedSecs() is invoked with the first round and a waiting time of less than 30s', () => { it('then it receives round 1 - no change ', async () => { - // assert both aggregated price and regular prices work as expected assert.equal( (await instance.getLastRoundIdBeforeElapsedSecs(sJPY, '1', 40, 10)).toString(), '1' ); - assert.equal( - (await instance.getLastRoundIdBeforeElapsedSecs(sBNB, '1', 40, 10)).toString(), - '1' - ); }); }); @@ -2046,10 +1064,6 @@ contract('Exchange Rates', async accounts => { (await instance.getLastRoundIdBeforeElapsedSecs(sJPY, '1', 40, 20)).toString(), '2' ); - assert.equal( - (await instance.getLastRoundIdBeforeElapsedSecs(sBNB, '1', 40, 20)).toString(), - '2' - ); }); }); @@ -2059,10 +1073,6 @@ contract('Exchange Rates', async accounts => { (await instance.getLastRoundIdBeforeElapsedSecs(sJPY, '2', 65, 25)).toString(), '3' ); - assert.equal( - (await instance.getLastRoundIdBeforeElapsedSecs(sBNB, '2', 65, 25)).toString(), - '3' - ); }); }); @@ -2072,10 +1082,6 @@ contract('Exchange Rates', async accounts => { (await instance.getLastRoundIdBeforeElapsedSecs(sJPY, '1', 40, 40)).toString(), '2' ); - assert.equal( - (await instance.getLastRoundIdBeforeElapsedSecs(sBNB, '1', 40, 40)).toString(), - '2' - ); }); }); describe('when getLastRoundIdBeforeElapsedSecs() is invoked with the first round and a waiting time of 60s exactly', () => { @@ -2084,10 +1090,6 @@ contract('Exchange Rates', async accounts => { (await instance.getLastRoundIdBeforeElapsedSecs(sJPY, '1', 50, 40)).toString(), '3' ); - assert.equal( - (await instance.getLastRoundIdBeforeElapsedSecs(sBNB, '1', 50, 40)).toString(), - '3' - ); }); }); describe('when getLastRoundIdBeforeElapsedSecs() is invoked with the first round and a waiting time beyond 60s', () => { @@ -2096,10 +1098,6 @@ contract('Exchange Rates', async accounts => { (await instance.getLastRoundIdBeforeElapsedSecs(sJPY, '1', 55, 6000)).toString(), '3' ); - assert.equal( - (await instance.getLastRoundIdBeforeElapsedSecs(sBNB, '1', 50, 40)).toString(), - '3' - ); }); }); describe('when getLastRoundIdBeforeElapsedSecs() is invoked with the third round and a waiting time beyond 60s', () => { @@ -2108,30 +1106,23 @@ contract('Exchange Rates', async accounts => { (await instance.getLastRoundIdBeforeElapsedSecs(sJPY, '3', 180, 9000)).toString(), '3' ); - assert.equal( - (await instance.getLastRoundIdBeforeElapsedSecs(sBNB, '1', 50, 40)).toString(), - '3' - ); }); }); }); }); + describe('effectiveValueAtRound()', () => { - describe('when both the aggregator and regular prices have been give three rates with current timestamps', () => { + describe('when both aggregated prices have been given three rates with current timestamps', () => { beforeEach(async () => { - let timestamp = await currentTime(); - await aggregatorJPY.setLatestAnswer(convertToDecimals(100, 8), timestamp); // round 1 for sJPY - await instance.updateRates([sBNB], [toUnit('1000')], timestamp, { from: oracle }); // round 1 for sBNB + await setupAggregators([sBNB]); + + await updateRates([sJPY, sBNB], [convertToDecimals(100, 8), toUnit('1000')]); await fastForward(120); - timestamp = await currentTime(); - await aggregatorJPY.setLatestAnswer(convertToDecimals(200, 8), timestamp); // round 2 for sJPY - await instance.updateRates([sBNB], [toUnit('2000')], timestamp, { from: oracle }); // round 2 for sBNB + await updateRates([sJPY, sBNB], [convertToDecimals(200, 8), toUnit('2000')]); await fastForward(120); - timestamp = await currentTime(); - await aggregatorJPY.setLatestAnswer(convertToDecimals(300, 8), timestamp); // round 3 for sJPY - await instance.updateRates([sBNB], [toUnit('4000')], timestamp, { from: oracle }); // round 3 for sBNB + await updateRates([sJPY, sBNB], [convertToDecimals(300, 8), toUnit('4000')]); }); it('accepts various changes to src roundId', async () => { assert.bnEqual( @@ -2989,20 +1980,28 @@ contract('Exchange Rates', async accounts => { }); }; + // utility function to setup price aggregators + async function setupAggregators(keys, decimalsArray = []) { + await setupPriceAggregators(instance, owner, keys, decimalsArray); + } + + // utility function update rates for aggregators that are already set up + async function updateRates(keys, rates, timestamp = undefined) { + await updateAggregatorRates(instance, keys, rates, timestamp); + } + describe('Using ExchangeRates', () => { const exchangeRatesContract = 'ExchangeRates'; before(async () => { - initialTime = await currentTime(); - ({ - ExchangeRates: instance, - SystemSettings: systemSettings, - AddressResolver: resolver, - } = await setupAllContracts({ + ({ ExchangeRates: instance, SystemSettings: systemSettings } = await setupAllContracts({ accounts, contracts: [exchangeRatesContract, 'SystemSettings', 'AddressResolver'], })); + // remove the pre-configured aggregator + await instance.removeAggregator(toBytes32('SNX'), { from: owner }); + aggregatorJPY = await MockAggregator.new({ from: owner }); aggregatorXTZ = await MockAggregator.new({ from: owner }); aggregatorFastGasPrice = await MockAggregator.new({ from: owner }); @@ -3017,22 +2016,10 @@ contract('Exchange Rates', async accounts => { addSnapshotBeforeRestoreAfterEach(); - beforeEach(async () => { - timeSent = await currentTime(); - }); - itIncludesCorrectMutativeFunctions(exchangeRatesContract); itIsConstructedCorrectly(exchangeRatesContract); - itUpdatesRates(); - - itSetsOracle(); - - itDeletesRates(); - - itReturnsRates(); - itCalculatesStaleRates(); itCalculatesInvalidRates(); @@ -3052,16 +2039,14 @@ contract('Exchange Rates', async accounts => { const exchangeRatesContract = 'ExchangeRatesWithDexPricing'; before(async () => { - initialTime = await currentTime(); - ({ - ExchangeRates: instance, - SystemSettings: systemSettings, - AddressResolver: resolver, - } = await setupAllContracts({ + ({ ExchangeRates: instance, SystemSettings: systemSettings } = await setupAllContracts({ accounts, contracts: [exchangeRatesContract, 'SystemSettings', 'AddressResolver'], })); + // remove the pre-configured aggregator + await instance.removeAggregator(toBytes32('SNX'), { from: owner }); + aggregatorJPY = await MockAggregator.new({ from: owner }); aggregatorXTZ = await MockAggregator.new({ from: owner }); aggregatorFastGasPrice = await MockAggregator.new({ from: owner }); @@ -3076,22 +2061,10 @@ contract('Exchange Rates', async accounts => { addSnapshotBeforeRestoreAfterEach(); - beforeEach(async () => { - timeSent = await currentTime(); - }); - itIncludesCorrectMutativeFunctions(exchangeRatesContract); itIsConstructedCorrectly(exchangeRatesContract); - itUpdatesRates(); - - itSetsOracle(); - - itDeletesRates(); - - itReturnsRates(); - itCalculatesStaleRates(); itCalculatesInvalidRates(); diff --git a/test/contracts/Exchanger.spec.js b/test/contracts/Exchanger.spec.js index 6a77044cfd..5a6f7c5000 100644 --- a/test/contracts/Exchanger.spec.js +++ b/test/contracts/Exchanger.spec.js @@ -18,6 +18,8 @@ const { setStatus, convertToAggregatorPrice, updateRatesWithDefaults, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { @@ -63,8 +65,6 @@ contract('Exchanger (spec tests)', async accounts => { sEURContract, sBTCContract, sETHContract, - oracle, - timestamp, exchanger, exchangeState, exchangeFeeRate, @@ -144,7 +144,7 @@ contract('Exchanger (spec tests)', async accounts => { const amountOfSrcExchanged = toUnit('10'); beforeEach(async () => { - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); await sUSDContract.issue(owner, toUnit('100')); await synthetix.exchange(sUSD, toUnit('10'), sETH, { from: owner }); }); @@ -278,9 +278,7 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { await fastForward(10); // base rate of sETH is 100 from shared setup above - await exchangeRates.updateRates([sETH], [toUnit('300')], await currentTime(), { - from: oracle, - }); + await updateRates([sETH], [toUnit('300')]); await synthetix.exchange(sUSD, toUnit('1'), sETH, { from: account1 }); }); it('then the synth is suspended', async () => { @@ -293,9 +291,7 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { await fastForward(10); // base rate of sETH is 100 from shared setup above - await exchangeRates.updateRates([sETH], [toUnit('33')], await currentTime(), { - from: oracle, - }); + await updateRates([sETH], [toUnit('33')]); await synthetix.exchange(sUSD, toUnit('1'), sETH, { from: account1 }); }); it('then the synth is suspended', async () => { @@ -313,9 +309,7 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { await fastForward(10); // base rate of sETH is 100 from shared setup above - await exchangeRates.updateRates([sETH], [toUnit('300')], await currentTime(), { - from: oracle, - }); + await updateRates([sETH], [toUnit('300')]); await synthetix.exchange(sUSD, toUnit('1'), sETH, { from: account1 }); }); it('then the synth is not suspended', async () => { @@ -328,9 +322,7 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { await fastForward(10); // base rate of sETH is 100 from shared setup above - await exchangeRates.updateRates([sETH], [toUnit('33')], await currentTime(), { - from: oracle, - }); + await updateRates([sETH], [toUnit('33')]); await synthetix.exchange(sUSD, toUnit('1'), sETH, { from: account1 }); }); it('then the synth is not suspended', async () => { @@ -574,47 +566,6 @@ contract('Exchanger (spec tests)', async accounts => { assert.bnEqual(amountReceived, effectiveValue.sub(tripleFee)); }); }); - describe('when sBTC price rate spike', () => { - let sUSDsBTCFee; - let sBTCBalance; - let sBTCsUSDFee; - beforeEach(async () => { - timestamp = await currentTime(); - await exchangeRates.updateRates([sETH, sBTC], ['110', '5100'].map(toUnit), timestamp, { - from: oracle, - }); - }); - describe('and swap sUSD to sBTC', () => { - let destinationFee; - beforeEach(async () => { - console.log('amountIssued', amountIssued.toString()); - await synthetix.exchange(sUSD, amountIssued, sBTC, { from: account1 }); - const { fee } = await exchanger.getAmountsForExchange(amountIssued, sUSD, sBTC); - destinationFee = fee; - }); - it('then destination fee is greater as included dynamic fee in destination currency', async () => { - const effectiveValue = await exchangeRates.effectiveValue(sUSD, amountIssued, sBTC); - sUSDsBTCFee = exchangeFeeIncurred(effectiveValue, bipsCrypto); - assert.bnGt(destinationFee, sUSDsBTCFee); - }); - it('then swap sBTC to sETH and fee is more than sUSD to sBTC as dynamic fee in both direction', async () => { - await fastForward(await systemSettings.waitingPeriodSecs()); - sBTCBalance = await sBTCContract.balanceOf(account1); - await synthetix.exchange(sBTC, sBTCBalance, sETH, { from: account1 }); - const { fee } = await exchanger.getAmountsForExchange(sBTCBalance, sBTC, sETH); - assert.bnGt(fee, destinationFee); - }); - it('then swap sBTC to sUSD and fee is greater as included dynamic fee in source currency', async () => { - await fastForward(await systemSettings.waitingPeriodSecs()); - sBTCBalance = await sBTCContract.balanceOf(account1); - await synthetix.exchange(sBTC, sBTCBalance, sUSD, { from: account1 }); - const { fee } = await exchanger.getAmountsForExchange(sBTCBalance, sBTC, sUSD); - const effectiveValue = await exchangeRates.effectiveValue(sBTC, sBTCBalance, sUSD); - sBTCsUSDFee = exchangeFeeIncurred(effectiveValue, bipsCrypto); - assert.bnGt(fee, sBTCsUSDFee); - }); - }); - }); }); }); }; @@ -716,14 +667,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('given the sEUR rate is 2, and sETH is 100, sBTC is 9000', () => { beforeEach(async () => { // set sUSD:sEUR as 2:1, sUSD:sETH at 100:1, sUSD:sBTC at 9000:1 - await exchangeRates.updateRates( - [sEUR, sETH, sBTC], - ['2', '100', '9000'].map(toUnit), - timestamp, - { - from: oracle, - } - ); + await updateRates([sEUR, sETH, sBTC], ['2', '100', '9000'].map(toUnit)); // Disable Dynamic Fee by setting rounds to 0 await systemSettings.setExchangeDynamicFeeRounds('0', { from: owner }); }); @@ -909,11 +853,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('when the price doubles for sUSD:sEUR to 4:1', () => { beforeEach(async () => { await fastForward(5); - timestamp = await currentTime(); - - await exchangeRates.updateRates([sEUR], ['4'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sEUR], ['4'].map(toUnit)); }); it('then settlement reclaimAmount shows a reclaim of half the entire balance of sEUR', async () => { const expected = calculateExpectedSettlementAmount({ @@ -1135,12 +1075,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('when the price halves for sUSD:sEUR to 1:1', () => { beforeEach(async () => { await fastForward(5); - - timestamp = await currentTime(); - - await exchangeRates.updateRates([sEUR], ['1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sEUR], ['1'].map(toUnit)); }); it('then settlement rebateAmount shows a rebate of half the entire balance of sEUR', async () => { const expected = calculateExpectedSettlementAmount({ @@ -1169,12 +1104,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('and then the price increases for sUSD:sEUR to 2:1', () => { beforeEach(async () => { await fastForward(5); - - timestamp = await currentTime(); - - await exchangeRates.updateRates([sEUR], ['2'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sEUR], ['2'].map(toUnit)); }); describe('when settlement is invoked', () => { describe('when another minute passes', () => { @@ -1383,12 +1313,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('when the price returns to sUSD:sEUR to 2:1', () => { beforeEach(async () => { await fastForward(12); - - timestamp = await currentTime(); - - await exchangeRates.updateRates([sEUR], ['2'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sEUR], ['2'].map(toUnit)); }); it('then settlement reclaimAmount shows 0 reclaim and 0 refund', async () => { const settlement = await exchanger.settlementOwing(account1, sEUR); @@ -1402,11 +1327,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('when another minute elapses and the sETH price changes', () => { beforeEach(async () => { await fastForward(60); - timestamp = await currentTime(); - - await exchangeRates.updateRates([sEUR], ['3'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sEUR], ['3'].map(toUnit)); }); it('then settlement reclaimAmount still shows 0 reclaim and 0 refund as the timeout period ended', async () => { const settlement = await exchanger.settlementOwing(account1, sEUR); @@ -1462,11 +1383,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('when the price doubles for sUSD:sEUR to 4:1', () => { beforeEach(async () => { await fastForward(5); - timestamp = await currentTime(); - - await exchangeRates.updateRates([sEUR], ['4'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sEUR], ['4'].map(toUnit)); }); it('then settlement shows a rebate rebateAmount', async () => { const { reclaimAmount, rebateAmount } = await exchanger.settlementOwing( @@ -1493,16 +1410,7 @@ contract('Exchanger (spec tests)', async accounts => { }); describe('when the price gains for sBTC more than the loss of the sEUR change', () => { beforeEach(async () => { - await fastForward(5); - timestamp = await currentTime(); - await exchangeRates.updateRates( - [sBTC], - ['20000'].map(toUnit), - timestamp, - { - from: oracle, - } - ); + await updateRates([sBTC], ['20000'].map(toUnit)); }); it('then the reclaimAmount is whats left when subtracting the rebate', async () => { const { reclaimAmount, rebateAmount } = await exchanger.settlementOwing( @@ -1557,16 +1465,8 @@ contract('Exchanger (spec tests)', async accounts => { let expectedFromSecond; beforeEach(async () => { await fastForward(5); - timestamp = await currentTime(); - - await exchangeRates.updateRates( - [sBTC], - ['10000'].map(toUnit), - timestamp, - { - from: oracle, - } - ); + + await updateRates([sBTC], ['10000'].map(toUnit)); expectedFromFirst = calculateExpectedSettlementAmount({ amount: amountOfSrcExchanged, @@ -1978,11 +1878,7 @@ contract('Exchanger (spec tests)', async accounts => { }); describe('when that synth has a fresh rate', () => { beforeEach(async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([sAUD], ['0.75'].map(toUnit), timestamp, { - from: oracle, - }); + await updateRates([sAUD], ['0.75'].map(toUnit)); }); describe(`when the user ${type} into that synth`, () => { beforeEach(async () => { @@ -2815,14 +2711,7 @@ contract('Exchanger (spec tests)', async accounts => { const updateRate = ({ target, rate }) => { beforeEach(async () => { await fastForward(10); - await exchangeRates.updateRates( - [target], - [toUnit(rate.toString())], - await currentTime(), - { - from: oracle, - } - ); + await updateRates([target], [toUnit(rate.toString())]); }); }; @@ -2907,13 +2796,10 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { // sETH over deviation and sEUR slight change await fastForward(10); - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sETH, sEUR], - [toUnit(baseRate * 3).toString(), toUnit('1.9')], - await currentTime(), - { - from: oracle, - } + [toUnit(baseRate * 3).toString(), toUnit('1.9')] ); }); describe('and another user exchanges sETH to sEUR', () => { @@ -2936,13 +2822,10 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { // sEUR over deviation and sETH slight change await fastForward(10); - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sETH, sEUR], - [toUnit(baseRate * 1.1).toString(), toUnit('10')], - await currentTime(), - { - from: oracle, - } + [toUnit(baseRate * 1.1).toString(), toUnit('10')] ); }); describe('and another user exchanges sEUR to sETH', () => { @@ -3134,21 +3017,12 @@ contract('Exchanger (spec tests)', async accounts => { describe('when a recent price rate is set way outside of the threshold', () => { beforeEach(async () => { await fastForward(10); - await exchangeRates.updateRates([sETH], [toUnit('1000')], await currentTime(), { - from: oracle, - }); + await updateRates([sETH], [toUnit('1000')]); }); describe('and then put back to normal', () => { beforeEach(async () => { await fastForward(10); - await exchangeRates.updateRates( - [sETH], - [baseRate.toString()], - await currentTime(), - { - from: oracle, - } - ); + await updateRates([sETH], [baseRate.toString()]); }); assertSpike({ from: sUSD, @@ -3568,9 +3442,14 @@ contract('Exchanger (spec tests)', async accounts => { }); }; + async function updateRates(keys, rates) { + await updateAggregatorRates(exchangeRates, keys, rates); + } + describe('With L1 configuration (Synthetix, ExchangerWithFeeRecAlternatives, ExchangeRatesWithDexPricing)', () => { before(async () => { const VirtualSynthMastercopy = artifacts.require('VirtualSynthMastercopy'); + const synths = ['sUSD', 'sETH', 'sEUR', 'sAUD', 'sBTC', 'iBTC', 'sTRX']; ({ Exchanger: exchanger, @@ -3592,7 +3471,7 @@ contract('Exchanger (spec tests)', async accounts => { FlexibleStorage: flexibleStorage, } = await setupAllContracts({ accounts, - synths: ['sUSD', 'sETH', 'sEUR', 'sAUD', 'sBTC', 'iBTC', 'sTRX'], + synths: synths, contracts: [ // L1 specific 'Synthetix', @@ -3616,8 +3495,7 @@ contract('Exchanger (spec tests)', async accounts => { }, })); - // Send a price update to guarantee we're not stale. - oracle = account1; + await setupPriceAggregators(exchangeRates, owner, synths.map(toBytes32)); amountIssued = toUnit('1000'); @@ -3630,18 +3508,12 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - await exchangeRates.updateRates( - [sAUD, sEUR, SNX, sETH, sBTC, iBTC], - ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit), - timestamp, - { - from: oracle, - } - ); + const keys = [sAUD, sEUR, SNX, sETH, sBTC, iBTC]; + const rates = ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit); + await setupPriceAggregators(exchangeRates, owner, keys); + await updateRates(keys, rates); } - // set a 0.5% exchange fee rate (1/200) exchangeFeeRate = toUnit('0.005'); await setExchangeFeeRateForSynths({ owner, @@ -3680,6 +3552,7 @@ contract('Exchanger (spec tests)', async accounts => { describe('With L2 configuration (MintableSynthetix, Exchanger, ExchangeRates)', () => { before(async () => { + const synths = ['sUSD', 'sETH', 'sEUR', 'sAUD', 'sBTC', 'iBTC', 'sTRX']; ({ Exchanger: exchanger, Synthetix: synthetix, @@ -3700,7 +3573,7 @@ contract('Exchanger (spec tests)', async accounts => { FlexibleStorage: flexibleStorage, } = await setupAllContracts({ accounts, - synths: ['sUSD', 'sETH', 'sEUR', 'sAUD', 'sBTC', 'iBTC', 'sTRX'], + synths: synths, contracts: [ // L2 specific 'MintableSynthetix', @@ -3720,8 +3593,7 @@ contract('Exchanger (spec tests)', async accounts => { ], })); - // Send a price update to guarantee we're not stale. - oracle = account1; + await setupPriceAggregators(exchangeRates, owner, synths.map(toBytes32)); amountIssued = toUnit('1000'); @@ -3734,15 +3606,10 @@ contract('Exchanger (spec tests)', async accounts => { beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - await exchangeRates.updateRates( - [sAUD, sEUR, SNX, sETH, sBTC, iBTC], - ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit), - timestamp, - { - from: oracle, - } - ); + const keys = [sAUD, sEUR, SNX, sETH, sBTC, iBTC]; + const rates = ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit); + await setupPriceAggregators(exchangeRates, owner, keys); + await updateRates(keys, rates); } // set a 0.5% exchange fee rate (1/200) diff --git a/test/contracts/FeePool.js b/test/contracts/FeePool.js index 2c14550911..7c22d40790 100644 --- a/test/contracts/FeePool.js +++ b/test/contracts/FeePool.js @@ -7,14 +7,7 @@ const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); const FeePool = artifacts.require('FeePool'); const FlexibleStorage = artifacts.require('FlexibleStorage'); -const { - currentTime, - fastForward, - toUnit, - toPreciseUnit, - fromUnit, - multiplyDecimal, -} = require('../utils')(); +const { fastForward, toUnit, toPreciseUnit, fromUnit, multiplyDecimal } = require('../utils')(); const { ensureOnlyExpectedMutativeFunctions, @@ -24,6 +17,8 @@ const { decodedEventEqual, proxyThruTo, setExchangeFeeRateForSynths, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { setupAllContracts } = require('./setup'); @@ -34,17 +29,12 @@ const { } = require('../..'); contract('FeePool', async accounts => { - const [deployerAccount, owner, oracle, account1, account2] = accounts; + const [deployerAccount, owner, , account1, account2] = accounts; // Updates rates with defaults so they're not stale. const updateRatesWithDefaults = async () => { - let timestamp; for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - - await exchangeRates.updateRates([sAUD, SNX], ['0.5', '0.1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sAUD, SNX], ['0.5', '0.1'].map(toUnit)); } await debtCache.takeDebtSnapshot(); }; @@ -121,6 +111,8 @@ contract('FeePool', async accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sAUD]); + FEE_ADDRESS = await feePool.FEE_ADDRESS(); }); @@ -828,15 +820,10 @@ contract('FeePool', async accounts => { .concat(synths) .filter(key => key !== 'sUSD' && ![].concat(type).includes(key)); - const timestamp = await currentTime(); - - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, ratesToUpdate.map(toBytes32), - ratesToUpdate.map(() => toUnit('1')), - timestamp, - { - from: oracle, - } + ratesToUpdate.map(() => toUnit('1')) ); await debtCache.takeDebtSnapshot(); }); @@ -1103,10 +1090,7 @@ contract('FeePool', async accounts => { // Increase the price so we start well and truly within our 20% ratio. const newRate = (await exchangeRates.rateForCurrency(SNX)).add(web3.utils.toBN('1')); - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [newRate], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [newRate]); await debtCache.takeDebtSnapshot(); assert.equal(await feePool.isFeesClaimable(owner), true); @@ -1120,10 +1104,7 @@ contract('FeePool', async accounts => { const newRate = (await exchangeRates.rateForCurrency(SNX)).add( step.mul(web3.utils.toBN('1')) ); - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [newRate], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [newRate]); await debtCache.takeDebtSnapshot(); const issuanceRatio = fromUnit(await feePool.issuanceRatio()); @@ -1145,10 +1126,7 @@ contract('FeePool', async accounts => { // Bump the rate down. const newRate = (await exchangeRates.rateForCurrency(SNX)).sub(step); - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [newRate], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [newRate]); await debtCache.takeDebtSnapshot(); } }); @@ -1180,10 +1158,7 @@ contract('FeePool', async accounts => { const currentRate = await exchangeRates.rateForCurrency(SNX); const newRate = currentRate.sub(multiplyDecimal(currentRate, toUnit('0.15'))); - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [newRate], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [newRate]); await debtCache.takeDebtSnapshot(); // fees available is unaffected but not claimable @@ -1223,10 +1198,7 @@ contract('FeePool', async accounts => { const currentRate = await exchangeRates.rateForCurrency(SNX); const newRate = currentRate.sub(multiplyDecimal(currentRate, toUnit('0.15'))); - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [newRate], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [newRate]); await debtCache.takeDebtSnapshot(); // fees available is unaffected but not claimable @@ -1327,15 +1299,10 @@ contract('FeePool', async accounts => { .concat(synths) .filter(key => key !== 'sUSD' && ![].concat(type).includes(key)); - const timestamp = await currentTime(); - - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, ratesToUpdate.map(toBytes32), - ratesToUpdate.map(() => toUnit('1')), - timestamp, - { - from: oracle, - } + ratesToUpdate.map(() => toUnit('1')) ); await debtCache.takeDebtSnapshot(); }); diff --git a/test/contracts/FeePoolState.js b/test/contracts/FeePoolState.js index 19542e204a..e88cc83c16 100644 --- a/test/contracts/FeePoolState.js +++ b/test/contracts/FeePoolState.js @@ -360,14 +360,11 @@ contract('FeePoolState', async accounts => { // TODO checks SynthetixState debt entry is same as stored FeePoolState Entry // it.only('should allow an issuer to issue max synths and track debt issuance in feePool', async function() { // // Send a price update to guarantee we're not depending on values from outside this test. - // const oracle = await exchangeRates.oracle(); - // const timestamp = await currentTime(); - // await exchangeRates.updateRates( + // await updateAggregatorRates( + // exchangeRates, // [sAUD, sEUR, SNX], - // ['0.5', '1.25', '0.1'].map(toUnit), - // timestamp, - // { from: oracle } + // ['0.5', '1.25', '0.1'].map(toUnit) // ); // // Give some SNX to account1 @@ -397,14 +394,11 @@ contract('FeePoolState', async accounts => { // it('should allow an issuer to issue synths many times and track debt issuance in feePool', async function() { // // Send a price update to guarantee we're not depending on values from outside this test. - // const oracle = await exchangeRates.oracle(); - // const timestamp = await currentTime(); - // await exchangeRates.updateRates( + // await updateAggregatorRates( + // exchangeRates, // [sAUD, sEUR, SNX], // ['0.5', '1.25', '0.1'].map(toUnit), - // timestamp, - // { from: oracle } // ); // // Give some SNX to account1 diff --git a/test/contracts/Issuer.js b/test/contracts/Issuer.js index d49754f592..febac572c5 100644 --- a/test/contracts/Issuer.js +++ b/test/contracts/Issuer.js @@ -25,6 +25,8 @@ const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions, setStatus, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { @@ -41,7 +43,7 @@ contract('Issuer (via Synthetix)', async accounts => { ); const synthKeys = [sUSD, sAUD, sEUR, sETH, SNX]; - const [, owner, oracle, account1, account2, account3, account6] = accounts; + const [, owner, , account1, account2, account3, account6] = accounts; let synthetix, systemStatus, @@ -56,7 +58,6 @@ contract('Issuer (via Synthetix)', async accounts => { sAUDContract, escrow, rewardEscrowV2, - timestamp, debtCache, issuer, synths, @@ -111,19 +112,18 @@ contract('Issuer (via Synthetix)', async accounts => { 'SynthRedeemer', ], })); + + await setupPriceAggregators(exchangeRates, owner, [sAUD, sEUR, sETH, ETH]); }); addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, SNX, sETH], - ['0.5', '1.25', '0.1', '200'].map(toUnit), - timestamp, - { from: oracle } + ['0.5', '1.25', '0.1', '200'].map(toUnit) ); } @@ -316,11 +316,10 @@ contract('Issuer (via Synthetix)', async accounts => { beforeEach(async () => { await fastForward(10); // Send a price update to give the synth rates - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, sEUR, sETH, ETH, SNX], - ['0.5', '1.25', '100', '100', '2'].map(toUnit), - await currentTime(), - { from: oracle } + ['0.5', '1.25', '100', '100', '2'].map(toUnit) ); await debtCache.takeDebtSnapshot(); }); @@ -398,8 +397,7 @@ contract('Issuer (via Synthetix)', async accounts => { describe('debtBalance()', () => { it('should not change debt balance % if exchange rates change', async () => { let newAUDRate = toUnit('0.5'); - let timestamp = await currentTime(); - await exchangeRates.updateRates([sAUD], [newAUDRate], timestamp, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sAUD], [newAUDRate]); await debtCache.takeDebtSnapshot(); await synthetix.transfer(account1, toUnit('20000'), { @@ -429,9 +427,8 @@ contract('Issuer (via Synthetix)', async accounts => { PRECISE_UNIT ); - timestamp = await currentTime(); newAUDRate = toUnit('1.85'); - await exchangeRates.updateRates([sAUD], [newAUDRate], timestamp, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sAUD], [newAUDRate]); await debtCache.takeDebtSnapshot(); totalIssuedSynthsUSD = await synthetix.totalIssuedSynths(sUSD); @@ -671,6 +668,7 @@ contract('Issuer (via Synthetix)', async accounts => { })); await issuer.addSynth(synth.address, { from: owner }); + await setupPriceAggregators(exchangeRates, owner, [currencyKey]); }); it('should be able to query multiple synth addresses', async () => { @@ -722,9 +720,7 @@ contract('Issuer (via Synthetix)', async accounts => { describe('when the synth has a rate', () => { beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - await exchangeRates.updateRates([currencyKey], [toUnit('2')], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [currencyKey], [toUnit('2')]); } }); @@ -743,17 +739,6 @@ contract('Issuer (via Synthetix)', async accounts => { const { numEntries } = await exchanger.settlementOwing(owner, currencyKey); assert.equal(numEntries, '0'); }); - describe('when the rate is also removed', () => { - beforeEach(async () => { - await exchangeRates.deleteRate(currencyKey, { from: oracle }); - }); - it('then settling works as expected', async () => { - await synthetix.settle(currencyKey); - - const { numEntries } = await exchanger.settlementOwing(owner, currencyKey); - assert.equal(numEntries, '0'); - }); - }); }); describe('when the same user exchanges out of the synth', () => { beforeEach(async () => { @@ -777,22 +762,6 @@ contract('Issuer (via Synthetix)', async accounts => { const { numEntries } = await exchanger.settlementOwing(owner, currencyKey); assert.equal(numEntries, '0'); }); - describe('when the rate is also removed', () => { - beforeEach(async () => { - await exchangeRates.deleteRate(currencyKey, { from: oracle }); - }); - it('then settling works as expected', async () => { - await synthetix.settle(currencyKey); - - const { numEntries } = await exchanger.settlementOwing(owner, currencyKey); - assert.equal(numEntries, '0'); - }); - it('then settling from the original currency works too', async () => { - await synthetix.settle(currencyKey); - const { numEntries } = await exchanger.settlementOwing(owner, currencyKey); - assert.equal(numEntries, '0'); - }); - }); }); }); }); @@ -1044,15 +1013,10 @@ contract('Issuer (via Synthetix)', async accounts => { .concat(synths) .filter(key => key !== 'sUSD' && ![].concat(type).includes(key)); - const timestamp = await currentTime(); - - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, ratesToUpdate.map(toBytes32), - ratesToUpdate.map(() => toUnit('1')), - timestamp, - { - from: oracle, - } + ratesToUpdate.map(() => toUnit('1')) ); await debtCache.takeDebtSnapshot(); }); @@ -1276,15 +1240,10 @@ contract('Issuer (via Synthetix)', async accounts => { .concat(synths) .filter(key => key !== 'sUSD' && ![].concat(type).includes(key)); - const timestamp = await currentTime(); - - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, ratesToUpdate.map(toBytes32), - ratesToUpdate.map(rate => toUnit(rate === 'SNX' ? '0.1' : '1')), - timestamp, - { - from: oracle, - } + ratesToUpdate.map(rate => toUnit(rate === 'SNX' ? '0.1' : '1')) ); await debtCache.takeDebtSnapshot(); }); @@ -1610,9 +1569,7 @@ contract('Issuer (via Synthetix)', async accounts => { from: owner, }); // Set SNX price to 1 - await exchangeRates.updateRates([SNX], ['1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['1'].map(toUnit)); await debtCache.takeDebtSnapshot(); // Issue await synthetix.issueMaxSynths({ from: account1 }); @@ -1625,9 +1582,7 @@ contract('Issuer (via Synthetix)', async accounts => { describe('when the SNX price drops 50%', () => { let maxIssuableSynths; beforeEach(async () => { - await exchangeRates.updateRates([SNX], ['.5'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['.5'].map(toUnit)); await debtCache.takeDebtSnapshot(); maxIssuableSynths = await synthetix.maxIssuableSynths(account1); assert.equal(await feePool.isFeesClaimable(account1), false); @@ -1649,9 +1604,7 @@ contract('Issuer (via Synthetix)', async accounts => { describe('when the SNX price drops 10%', () => { let maxIssuableSynths; beforeEach(async () => { - await exchangeRates.updateRates([SNX], ['.9'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['.9'].map(toUnit)); await debtCache.takeDebtSnapshot(); maxIssuableSynths = await synthetix.maxIssuableSynths(account1); }); @@ -1672,9 +1625,7 @@ contract('Issuer (via Synthetix)', async accounts => { describe('when the SNX price drops 90%', () => { let maxIssuableSynths; beforeEach(async () => { - await exchangeRates.updateRates([SNX], ['.1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['.1'].map(toUnit)); await debtCache.takeDebtSnapshot(); maxIssuableSynths = await synthetix.maxIssuableSynths(account1); }); @@ -1695,9 +1646,7 @@ contract('Issuer (via Synthetix)', async accounts => { describe('when the SNX price increases 100%', () => { let maxIssuableSynths; beforeEach(async () => { - await exchangeRates.updateRates([SNX], ['2'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], ['2'].map(toUnit)); await debtCache.takeDebtSnapshot(); maxIssuableSynths = await synthetix.maxIssuableSynths(account1); }); @@ -1784,9 +1733,7 @@ contract('Issuer (via Synthetix)', async accounts => { }); describe('and the sEUR price decreases by 20% to 1', () => { beforeEach(async () => { - await exchangeRates.updateRates([sEUR], ['1'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sEUR], ['1'].map(toUnit)); await debtCache.takeDebtSnapshot(); }); describe('and 60s elapses', () => { @@ -2109,8 +2056,7 @@ contract('Issuer (via Synthetix)', async accounts => { it("should prevent more issuance if the user's collaterisation changes to be insufficient", async () => { // Set sEUR for purposes of this test - const timestamp1 = await currentTime(); - await exchangeRates.updateRates([sEUR], [toUnit('0.75')], timestamp1, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sEUR], [toUnit('0.75')]); await debtCache.takeDebtSnapshot(); const issuedSynthetixs = web3.utils.toBN('200000'); @@ -2129,8 +2075,7 @@ contract('Issuer (via Synthetix)', async accounts => { await synthetix.exchange(sUSD, issuedSynths, sEUR, { from: account1 }); // Increase the value of sEUR relative to synthetix - const timestamp2 = await currentTime(); - await exchangeRates.updateRates([sEUR], [toUnit('1.10')], timestamp2, { from: oracle }); + await updateAggregatorRates(exchangeRates, [sEUR], [toUnit('1.1')]); await debtCache.takeDebtSnapshot(); await assert.revert( @@ -2431,7 +2376,7 @@ contract('Issuer (via Synthetix)', async accounts => { await synthetix.transfer(authoriser, toUnit('20000'), { from: owner, }); - await exchangeRates.updateRates([SNX], ['1'].map(toUnit), timestamp, { from: oracle }); + await updateAggregatorRates(exchangeRates, [SNX], [toUnit('1')]); await debtCache.takeDebtSnapshot(); }); describe('when not approved it should revert on', async () => { @@ -2518,9 +2463,7 @@ contract('Issuer (via Synthetix)', async accounts => { }); it('and calling burnSynthsToTargetOnBehalf() succeeds', async () => { // need the user to be undercollaterized for this to succeed - await exchangeRates.updateRates([SNX], ['0.001'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [toUnit('0.001')]); await debtCache.takeDebtSnapshot(); await synthetix.burnSynthsToTargetOnBehalf(authoriser, { from: delegate }); }); @@ -2570,7 +2513,7 @@ contract('Issuer (via Synthetix)', async accounts => { }); it('should approveBurnOnBehalf and burnSynthsToTarget', async () => { await synthetix.issueMaxSynths({ from: authoriser }); - await exchangeRates.updateRates([SNX], ['0.01'].map(toUnit), timestamp, { from: oracle }); + await updateAggregatorRates(exchangeRates, [SNX], [toUnit('0.01')]); await debtCache.takeDebtSnapshot(); await delegateApprovals.approveBurnOnBehalf(delegate, { from: authoriser }); diff --git a/test/contracts/Liquidations.js b/test/contracts/Liquidations.js index 2f4bef7079..1255160b68 100644 --- a/test/contracts/Liquidations.js +++ b/test/contracts/Liquidations.js @@ -12,6 +12,7 @@ const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions, setStatus, + updateAggregatorRates, } = require('./helpers'); const { @@ -24,7 +25,7 @@ const FlexibleStorage = artifacts.require('FlexibleStorage'); contract('Liquidations', accounts => { const [sUSD, SNX] = ['sUSD', 'SNX'].map(toBytes32); - const [deployerAccount, owner, oracle, account1, alice, bob, carol, david] = accounts; + const [deployerAccount, owner, , account1, alice, bob, carol, david] = accounts; const week = 3600 * 24 * 7; const sUSD100 = toUnit('100'); @@ -38,8 +39,7 @@ contract('Liquidations', accounts => { systemStatus, feePoolState, debtCache, - issuer, - timestamp; + issuer; // run this once before all tests to prepare our environment, snapshots on beforeEach will take // care of resetting to this state @@ -86,16 +86,11 @@ contract('Liquidations', accounts => { }; const updateRatesWithDefaults = async () => { - timestamp = await currentTime(); - // SNX is 6 dolla await updateSNXPrice('6'); }; const updateSNXPrice = async rate => { - timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [rate].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [rate].map(toUnit)); await debtCache.takeDebtSnapshot(); }; diff --git a/test/contracts/MultiCollateralSynth.js b/test/contracts/MultiCollateralSynth.js index 60e92c1c7c..165a13186a 100644 --- a/test/contracts/MultiCollateralSynth.js +++ b/test/contracts/MultiCollateralSynth.js @@ -6,8 +6,13 @@ const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); let MultiCollateralSynth; -const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions } = require('./helpers'); -const { toUnit, currentTime, fastForward } = require('../utils')(); +const { + onlyGivenAddressCanInvoke, + ensureOnlyExpectedMutativeFunctions, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); +const { toUnit, fastForward } = require('../utils')(); const { toBytes32, constants: { ZERO_ADDRESS }, @@ -16,9 +21,10 @@ const { const { setupAllContracts } = require('./setup'); contract('MultiCollateralSynth', accounts => { - const [deployerAccount, owner, oracle, , account1] = accounts; + const [deployerAccount, owner, , , account1] = accounts; const sETH = toBytes32('sETH'); + const sBTC = toBytes32('sBTC'); let issuer, resolver, @@ -43,20 +49,6 @@ contract('MultiCollateralSynth', accounts => { }); }; - const updateRatesWithDefaults = async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); - - const sBTC = toBytes32('sBTC'); - - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); - }; - before(async () => { MultiCollateralSynth = artifacts.require('MultiCollateralSynth'); }); @@ -91,6 +83,9 @@ contract('MultiCollateralSynth', accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sETH, sBTC]); + await updateAggregatorRates(exchangeRates, [sETH, sBTC], [100, 10000].map(toUnit)); + await managerState.setAssociatedContract(manager.address, { from: owner }); await manager.rebuildCache(); @@ -99,8 +94,6 @@ contract('MultiCollateralSynth', accounts => { await manager.addCollaterals([ceth.address], { from: owner }); - await updateRatesWithDefaults(); - await issuesUSDToAccount(toUnit(1000), owner); await debtCache.takeDebtSnapshot(); }); @@ -199,11 +192,9 @@ contract('MultiCollateralSynth', accounts => { describe('when multiCollateral is set to the owner', () => { beforeEach(async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([toBytes32('sXYZ')], [toUnit(5)], timestamp, { - from: oracle, - }); + const sXYZ = toBytes32('sXYZ'); + await setupPriceAggregators(exchangeRates, owner, [sXYZ]); + await updateAggregatorRates(exchangeRates, [sXYZ], [toUnit(5)]); }); describe('when multiCollateral tries to issue', () => { it('then it can issue new synths', async () => { diff --git a/test/contracts/NativeEtherWrapper.js b/test/contracts/NativeEtherWrapper.js index 920891fcb2..c305cb4327 100644 --- a/test/contracts/NativeEtherWrapper.js +++ b/test/contracts/NativeEtherWrapper.js @@ -4,13 +4,15 @@ const { contract, web3 } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { currentTime, toUnit } = require('../utils')(); +const { toUnit } = require('../utils')(); const { GAS_PRICE } = require('../../hardhat.config'); const { ensureOnlyExpectedMutativeFunctions, getDecodedLogs, decodedEventEqual, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { setupAllContracts } = require('./setup'); @@ -22,7 +24,7 @@ contract('NativeEtherWrapper', async accounts => { const synths = ['sUSD', 'sETH', 'ETH', 'SNX']; const [sETH, ETH] = ['sETH', 'ETH'].map(toBytes32); - const [, owner, oracle, , account1] = accounts; + const [, owner, , , account1] = accounts; let systemSettings, exchangeRates, @@ -30,8 +32,7 @@ contract('NativeEtherWrapper', async accounts => { sETHSynth, etherWrapper, nativeEtherWrapper, - weth, - timestamp; + weth; before(async () => { ({ @@ -63,12 +64,10 @@ contract('NativeEtherWrapper', async accounts => { ], })); - timestamp = await currentTime(); + await setupPriceAggregators(exchangeRates, owner, [sETH, ETH]); // Depot requires ETH rates - await exchangeRates.updateRates([sETH, ETH], ['1500', '1500'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH, ETH], ['1500', '1500'].map(toUnit)); }); addSnapshotBeforeRestoreAfterEach(); diff --git a/test/contracts/PurgeableSynth.js b/test/contracts/PurgeableSynth.js index 1c5d53e550..d3f0137022 100644 --- a/test/contracts/PurgeableSynth.js +++ b/test/contracts/PurgeableSynth.js @@ -8,7 +8,7 @@ const TokenState = artifacts.require('TokenState'); const Proxy = artifacts.require('Proxy'); const PurgeableSynth = artifacts.require('PurgeableSynth'); -const { currentTime, fastForward, toUnit } = require('../utils')(); +const { fastForward, toUnit } = require('../utils')(); const { toBytes32, defaults: { EXCHANGE_DYNAMIC_FEE_ROUNDS }, @@ -21,6 +21,8 @@ const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions, setStatus, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { setupAllContracts } = require('./setup'); @@ -28,7 +30,7 @@ const { setupAllContracts } = require('./setup'); contract('PurgeableSynth', accounts => { const [sUSD, SNX, sAUD, iETH] = ['sUSD', 'SNX', 'sAUD', 'iETH'].map(toBytes32); const synthKeys = [sUSD, sAUD, iETH]; - const [deployerAccount, owner, oracle, , account1, account2] = accounts; + const [deployerAccount, owner, , , account1, account2] = accounts; let exchangeRates, exchanger, @@ -37,7 +39,6 @@ contract('PurgeableSynth', accounts => { sAUDContract, iETHContract, systemStatus, - timestamp, addressResolver, debtCache, issuer; @@ -72,7 +73,7 @@ contract('PurgeableSynth', accounts => { ], })); - timestamp = await currentTime(); + await setupPriceAggregators(exchangeRates, owner, [sAUD, iETH]); }); beforeEach(async () => { @@ -157,13 +158,10 @@ contract('PurgeableSynth', accounts => { describe("when there's a price for the purgeable synth", () => { beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - await exchangeRates.updateRates( + await updateAggregatorRates( + exchangeRates, [sAUD, SNX, iETH], - ['0.5', '1', '170'].map(toUnit), - timestamp, - { - from: oracle, - } + ['0.5', '1', '170'].map(toUnit) ); } await debtCache.takeDebtSnapshot(); @@ -210,9 +208,7 @@ contract('PurgeableSynth', accounts => { }); describe('when rates are received', () => { beforeEach(async () => { - await exchangeRates.updateRates([iETH], ['170'].map(toUnit), await currentTime(), { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [iETH], ['170'].map(toUnit)); await debtCache.takeDebtSnapshot(); }); it('then purge() still works as expected', async () => { @@ -326,9 +322,7 @@ contract('PurgeableSynth', accounts => { describe('when sAUD has a price', () => { beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - await exchangeRates.updateRates([sAUD], ['0.776845993'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sAUD], ['0.776845993'].map(toUnit)); } await debtCache.takeDebtSnapshot(); }); diff --git a/test/contracts/RewardsIntegrationTests.js b/test/contracts/RewardsIntegrationTests.js index 84f280bb0d..f50af7f70c 100644 --- a/test/contracts/RewardsIntegrationTests.js +++ b/test/contracts/RewardsIntegrationTests.js @@ -4,14 +4,16 @@ const { contract, web3 } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { - toBytes32, - defaults: { EXCHANGE_DYNAMIC_FEE_ROUNDS }, -} = require('../..'); +const { toBytes32 } = require('../..'); -const { currentTime, fastForward, toUnit, toPreciseUnit, multiplyDecimal } = require('../utils')(); +const { fastForward, toUnit, toPreciseUnit, multiplyDecimal } = require('../utils')(); -const { setExchangeFeeRateForSynths } = require('./helpers'); +const { + setExchangeFeeRateForSynths, + setupPriceAggregators, + updateRatesWithDefaults, + updateAggregatorRates, +} = require('./helpers'); const { setupAllContracts } = require('./setup'); @@ -63,25 +65,6 @@ contract('Rewards Integration Tests', accounts => { const synthKeys = [sUSD, sAUD, sEUR, sBTC, iBTC, sETH, ETH]; - // Updates rates with defaults so they're not stale. - const updateRatesWithDefaults = async () => { - let timestamp; - for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - - await exchangeRates.updateRates( - [sAUD, sEUR, SNX, sBTC, iBTC, sETH, ETH], - ['0.5', '1.25', '0.1', '5000', '4000', '172', '172'].map(toUnit), - timestamp, - { - from: oracle, - } - ); - } - - await debtCache.takeDebtSnapshot(); - }; - const fastForwardAndCloseFeePeriod = async () => { const feePeriodDuration = await feePool.feePeriodDuration(); // Note: add on a small addition of 10 seconds - this seems to have @@ -93,12 +76,12 @@ contract('Rewards Integration Tests', accounts => { // Fast forward another day after feePeriod closed before minting await fastForward(DAY + 10); - await updateRatesWithDefaults(); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); }; const fastForwardAndUpdateRates = async seconds => { await fastForward(seconds); - await updateRatesWithDefaults(); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); }; const exchangeFeeRate = toUnit('0.003'); // 30 bips @@ -136,7 +119,7 @@ contract('Rewards Integration Tests', accounts => { // const YEAR = 31556926; // ACCOUNTS - const [deployerAccount, owner, oracle, feeAuthority, account1, account2, account3] = accounts; + const [deployerAccount, owner, , feeAuthority, account1, account2, account3] = accounts; // VARIABLES let feePool, @@ -187,6 +170,8 @@ contract('Rewards Integration Tests', accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sAUD, sEUR, sBTC, iBTC, sETH, ETH]); + MINTER_SNX_REWARD = await supplySchedule.minterReward(); await setExchangeFeeRateForSynths({ @@ -633,10 +618,7 @@ contract('Rewards Integration Tests', accounts => { ); // Increase sBTC price by 100% - const timestamp = await currentTime(); - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], ['10000'].map(toUnit)); await debtCache.takeDebtSnapshot(); // Account 3 (enters the system and) mints 10K sUSD (minus half of an exchange fee - to balance the fact @@ -934,10 +916,7 @@ contract('Rewards Integration Tests', accounts => { const currentRate = await exchangeRates.rateForCurrency(SNX); const newRate = currentRate.sub(multiplyDecimal(currentRate, toUnit('0.009'))); - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [newRate], timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [SNX], [newRate]); // we will be able to claim fees assert.equal(await feePool.isFeesClaimable(account1), true); @@ -959,11 +938,7 @@ contract('Rewards Integration Tests', accounts => { it('should block user from claiming fees and rewards when users claim rewards >10% threshold collateralisation ratio', async () => { // But if the price of SNX decreases a lot... const newRate = (await exchangeRates.rateForCurrency(SNX)).sub(toUnit('0.09')); - const timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], [newRate], timestamp, { - from: oracle, - }); - + await updateAggregatorRates(exchangeRates, [SNX], [newRate]); // we will fall into the >100% bracket assert.equal(await feePool.isFeesClaimable(account1), false); diff --git a/test/contracts/ShortingRewards.js b/test/contracts/ShortingRewards.js index 4c6de47f63..4915282112 100644 --- a/test/contracts/ShortingRewards.js +++ b/test/contracts/ShortingRewards.js @@ -5,7 +5,12 @@ const { toBytes32, constants: { ZERO_ADDRESS }, } = require('../..'); -const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions } = require('./helpers'); +const { + onlyGivenAddressCanInvoke, + ensureOnlyExpectedMutativeFunctions, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); const { setupAllContracts, setupContract } = require('./setup'); const { currentTime, toUnit, fastForward } = require('../utils')(); @@ -17,7 +22,7 @@ contract('ShortingRewards', accounts => { const [ deployerAccount, owner, - oracle, + , authority, rewardEscrowAddress, account1, @@ -27,7 +32,9 @@ contract('ShortingRewards', accounts => { const sUSD = toBytes32('sUSD'); const sETH = toBytes32('sETH'); + const iETH = toBytes32('iETH'); const sBTC = toBytes32('sBTC'); + const iBTC = toBytes32('iBTC'); // Synthetix is the rewardsToken let rewardsToken, @@ -57,33 +64,11 @@ contract('ShortingRewards', accounts => { return event.args.id; }; - const updateRatesWithDefaults = async () => { - const timestamp = await currentTime(); - - await exchangeRates.updateRates([sETH], ['100'].map(toUnit), timestamp, { - from: oracle, - }); - - const sBTC = toBytes32('sBTC'); - - await exchangeRates.updateRates([sBTC], ['10000'].map(toUnit), timestamp, { - from: oracle, - }); - }; - const setRewardsTokenExchangeRate = async ({ rateStaleDays } = { rateStaleDays: 7 }) => { const rewardsTokenIdentifier = await rewardsToken.symbol(); await systemSettings.setRateStalePeriod(DAY * rateStaleDays, { from: owner }); - const updatedTime = await currentTime(); - await exchangeRates.updateRates( - [toBytes32(rewardsTokenIdentifier)], - [toUnit('2')], - updatedTime, - { - from: oracle, - } - ); + await updateAggregatorRates(exchangeRates, [toBytes32(rewardsTokenIdentifier)], [toUnit('2')]); assert.equal(await exchangeRates.rateIsStale(toBytes32(rewardsTokenIdentifier)), false); }; @@ -150,6 +135,8 @@ contract('ShortingRewards', accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sBTC, iBTC, sETH, iETH]); + managerState = await CollateralManagerState.new(owner, ZERO_ADDRESS, { from: deployerAccount }); const maxDebt = toUnit(10000000); @@ -232,7 +219,7 @@ contract('ShortingRewards', accounts => { }); beforeEach(async () => { - await updateRatesWithDefaults(); + await updateAggregatorRates(exchangeRates, [sETH, sBTC], [100, 10000].map(toUnit)); await issuesUSDToAccount(toUnit(100000), owner); await issuesBTCtoAccount(toUnit(10), owner); @@ -443,10 +430,7 @@ contract('ShortingRewards', accounts => { await fastForward(DAY); // Make the short so underwater it must get closed. - const timestamp = await currentTime(); - await exchangeRates.updateRates([sBTC], ['20000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], ['20000'].map(toUnit)); // close the loan via liquidation await issuesBTCtoAccount(toUnit(1), account2); @@ -465,10 +449,7 @@ contract('ShortingRewards', accounts => { await fastForward(DAY); // Make the short so underwater it must get closed. - const timestamp = await currentTime(); - await exchangeRates.updateRates([sBTC], ['20000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sBTC], ['20000'].map(toUnit)); // close the loan via liquidation await issuesBTCtoAccount(toUnit(1), account2); diff --git a/test/contracts/StakingRewards.js b/test/contracts/StakingRewards.js index 59a94833ef..ae19180d18 100644 --- a/test/contracts/StakingRewards.js +++ b/test/contracts/StakingRewards.js @@ -2,7 +2,12 @@ const { contract } = require('hardhat'); const { toBN } = require('web3-utils'); const { toBytes32 } = require('../..'); -const { onlyGivenAddressCanInvoke, ensureOnlyExpectedMutativeFunctions } = require('./helpers'); +const { + onlyGivenAddressCanInvoke, + ensureOnlyExpectedMutativeFunctions, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); const { mockToken, setupAllContracts, setupContract } = require('./setup'); const { currentTime, toUnit, fastForward } = require('../utils')(); @@ -11,7 +16,7 @@ contract('StakingRewards', accounts => { const [ , owner, - oracle, + , authority, rewardEscrowAddress, stakingAccount1, @@ -33,18 +38,12 @@ contract('StakingRewards', accounts => { const setRewardsTokenExchangeRate = async ({ rateStaleDays } = { rateStaleDays: 7 }) => { const rewardsTokenIdentifier = await rewardsToken.symbol(); + const tokenKey = toBytes32(rewardsTokenIdentifier); await systemSettings.setRateStalePeriod(DAY * rateStaleDays, { from: owner }); - const updatedTime = await currentTime(); - await exchangeRates.updateRates( - [toBytes32(rewardsTokenIdentifier)], - [toUnit('2')], - updatedTime, - { - from: oracle, - } - ); - assert.equal(await exchangeRates.rateIsStale(toBytes32(rewardsTokenIdentifier)), false); + await setupPriceAggregators(exchangeRates, owner, [tokenKey]); + await updateAggregatorRates(exchangeRates, [tokenKey], [toUnit('2')]); + assert.equal(await exchangeRates.rateIsStale(tokenKey), false); }; addSnapshotBeforeRestoreAfterEach(); diff --git a/test/contracts/Synth.js b/test/contracts/Synth.js index a9e1833265..bae72386bc 100644 --- a/test/contracts/Synth.js +++ b/test/contracts/Synth.js @@ -9,12 +9,14 @@ const Synth = artifacts.require('Synth'); const { setupAllContracts } = require('./setup'); -const { currentTime, toUnit, bytesToString } = require('../utils')(); +const { toUnit, bytesToString } = require('../utils')(); const { issueSynthsToUser, ensureOnlyExpectedMutativeFunctions, onlyGivenAddressCanInvoke, setStatus, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { @@ -26,7 +28,7 @@ const { contract('Synth', async accounts => { const [sUSD, SNX, sEUR] = ['sUSD', 'SNX', 'sEUR'].map(toBytes32); - const [deployerAccount, owner, oracle, , account1, account2] = accounts; + const [deployerAccount, owner, , , account1, account2] = accounts; let feePool, FEE_ADDRESS, @@ -72,20 +74,17 @@ contract('Synth', async accounts => { ], })); + await setupPriceAggregators(exchangeRates, owner, [sEUR]); + FEE_ADDRESS = await feePool.FEE_ADDRESS(); }); addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { - let timestamp; - - // Send a price update to guarantee we're not stale. for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - await exchangeRates.updateRates([SNX], ['0.1'].map(toUnit), timestamp, { - from: oracle, - }); + // Send a price update to guarantee we're not stale. + await updateAggregatorRates(exchangeRates, [SNX], ['0.1'].map(toUnit)); } await debtCache.takeDebtSnapshot(); @@ -737,14 +736,9 @@ contract('Synth', async accounts => { contracts: [{ contract: 'Synth', properties: { currencyKey: sEUR } }], })); - let timestamp; - - // Send a price update to guarantee we're not stale. for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - await exchangeRates.updateRates([sEUR], ['1'].map(toUnit), timestamp, { - from: oracle, - }); + // Send a price update to guarantee we're not stale. + await updateAggregatorRates(exchangeRates, [sEUR], ['1'].map(toUnit)); } await debtCache.takeDebtSnapshot(); }); diff --git a/test/contracts/SynthUtil.js b/test/contracts/SynthUtil.js index afbd47d4ba..6c8506b9f3 100644 --- a/test/contracts/SynthUtil.js +++ b/test/contracts/SynthUtil.js @@ -6,16 +6,20 @@ const { toBytes32, defaults: { EXCHANGE_DYNAMIC_FEE_ROUNDS }, } = require('../..'); -const { toUnit, currentTime } = require('../utils')(); -const { setExchangeFeeRateForSynths } = require('./helpers'); +const { toUnit } = require('../utils')(); +const { + setExchangeFeeRateForSynths, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { setupAllContracts } = require('./setup'); contract('SynthUtil', accounts => { - const [, ownerAccount, oracle, account2] = accounts; - let synthUtil, sUSDContract, synthetix, exchangeRates, timestamp, systemSettings, debtCache; + const [, ownerAccount, , account2] = accounts; + let synthUtil, sUSDContract, synthetix, exchangeRates, systemSettings, debtCache; - const [sUSD, sBTC, iBTC] = ['sUSD', 'sBTC', 'iBTC'].map(toBytes32); + const [sUSD, sBTC, iBTC, SNX] = ['sUSD', 'sBTC', 'iBTC', 'SNX'].map(toBytes32); const synthKeys = [sUSD, sBTC, iBTC]; const synthPrices = [toUnit('1'), toUnit('5000'), toUnit('5000')]; @@ -45,16 +49,19 @@ contract('SynthUtil', accounts => { 'RewardEscrowV2', // required for issuer._collateral to read collateral ], })); + + await setupPriceAggregators(exchangeRates, ownerAccount, [sBTC, iBTC]); }); addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - await exchangeRates.updateRates([sBTC, iBTC], ['5000', '5000'].map(toUnit), timestamp, { - from: oracle, - }); + await updateAggregatorRates( + exchangeRates, + [sBTC, iBTC, SNX], + ['5000', '5000', '0.2'].map(toUnit) + ); } await debtCache.takeDebtSnapshot(); diff --git a/test/contracts/Synthetix.js b/test/contracts/Synthetix.js index a7a5159c6d..a7de48399f 100644 --- a/test/contracts/Synthetix.js +++ b/test/contracts/Synthetix.js @@ -15,6 +15,7 @@ const { fastForwardTo, toUnit, fromUnit } = require('../utils')(); const { ensureOnlyExpectedMutativeFunctions, updateRatesWithDefaults, + setupPriceAggregators, setStatus, } = require('./helpers'); @@ -34,7 +35,6 @@ contract('Synthetix', async accounts => { supplySchedule, rewardEscrow, rewardEscrowV2, - oracle, addressResolver, systemStatus, sUSDContract, @@ -72,8 +72,7 @@ contract('Synthetix', async accounts => { ], })); - // Send a price update to guarantee we're not stale. - oracle = account1; + await setupPriceAggregators(exchangeRates, owner, [sAUD, sEUR, sETH]); }); addSnapshotBeforeRestoreAfterEach(); @@ -187,7 +186,7 @@ contract('Synthetix', async accounts => { // ensure mint() can succeed by default const week234 = INFLATION_START_DATE + WEEK * 234; await fastForwardTo(new Date(week234 * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); }); ['System', 'Issuance'].forEach(section => { describe(`when ${section} is suspended`, () => { @@ -212,7 +211,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to end of inflation supply decay at week 234 const week234 = INFLATION_START_DATE + WEEK * 234; await fastForwardTo(new Date(week234 * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); const existingSupply = await synthetix.totalSupply(); const mintableSupply = await supplySchedule.mintableSupply(); @@ -248,7 +247,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to Week 3 in of the inflationary supply const weekThree = INFLATION_START_DATE + WEEK * 2 + DAY; await fastForwardTo(new Date(weekThree * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); const existingSupply = await synthetix.totalSupply(); const mintableSupply = await supplySchedule.mintableSupply(); @@ -285,7 +284,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to Week 2 in Year 3 schedule starting at UNIX 1583971200+ const weekThirtyNine = INFLATION_START_DATE + WEEK * 39 + DAY; await fastForwardTo(new Date(weekThirtyNine * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); const existingTotalSupply = await synthetix.totalSupply(); const currentRewardEscrowBalance = await synthetix.balanceOf(rewardEscrow.address); @@ -312,7 +311,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to week 236 const september142023 = INFLATION_START_DATE + 236 * WEEK + DAY; await fastForwardTo(new Date(september142023 * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); const existingTotalSupply = await synthetix.totalSupply(); const mintableSupply = await supplySchedule.mintableSupply(); @@ -334,7 +333,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to week 236 const week573 = INFLATION_START_DATE + 572 * WEEK + DAY; await fastForwardTo(new Date(week573 * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); const existingTotalSupply = await synthetix.totalSupply(); const mintableSupply = await supplySchedule.mintableSupply(); @@ -356,7 +355,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to Week 3 in Year 2 schedule starting at UNIX 1553040000+ const weekThree = INFLATION_START_DATE + 2 * WEEK + 1 * DAY; await fastForwardTo(new Date(weekThree * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); let existingTotalSupply = await synthetix.totalSupply(); let mintableSupply = await supplySchedule.mintableSupply(); @@ -370,7 +369,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to Week 4 const weekFour = weekThree + 1 * WEEK + 1 * DAY; await fastForwardTo(new Date(weekFour * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); existingTotalSupply = await synthetix.totalSupply(); mintableSupply = await supplySchedule.mintableSupply(); @@ -386,7 +385,7 @@ contract('Synthetix', async accounts => { // fast forward EVM to Week 3 of inflation const weekThree = INFLATION_START_DATE + 2 * WEEK + DAY; await fastForwardTo(new Date(weekThree * 1000)); - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); const existingTotalSupply = await synthetix.totalSupply(); const mintableSupply = await supplySchedule.mintableSupply(); @@ -444,7 +443,7 @@ contract('Synthetix', async accounts => { contractExample = await MockThirdPartyExchangeContract.new(addressResolver.address); // ensure rates are set - await updateRatesWithDefaults({ exchangeRates, oracle, debtCache }); + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); // issue sUSD from the owner await synthetix.issueSynths(amountOfsUSD, { from: owner }); diff --git a/test/contracts/TradingRewards.spec.js b/test/contracts/TradingRewards.spec.js index 69bf8fcf9e..ff3e7f80d5 100644 --- a/test/contracts/TradingRewards.spec.js +++ b/test/contracts/TradingRewards.spec.js @@ -2,8 +2,14 @@ const { contract, web3 } = require('hardhat'); const { toBN } = web3.utils; const { assert, addSnapshotBeforeRestoreAfter } = require('./common'); const { setupAllContracts } = require('./setup'); -const { currentTime, toUnit, multiplyDecimal } = require('../utils')(); -const { setExchangeFeeRateForSynths, getDecodedLogs, decodedEventEqual } = require('./helpers'); +const { toUnit, multiplyDecimal } = require('../utils')(); +const { + setExchangeFeeRateForSynths, + getDecodedLogs, + decodedEventEqual, + setupPriceAggregators, + updateAggregatorRates, +} = require('./helpers'); const { toBytes32, defaults: { EXCHANGE_DYNAMIC_FEE_ROUNDS }, @@ -18,9 +24,9 @@ const { contract('TradingRewards', accounts => { const [, owner, account1] = accounts; - const synths = ['sUSD', 'sETH', 'sBTC']; + const synths = ['sUSD', 'sETH', 'sBTC', 'SNX']; const synthKeys = synths.map(toBytes32); - const [sUSD, sETH, sBTC] = synthKeys; + const [sUSD, sETH, sBTC, SNX] = synthKeys; let synthetix, exchanger, exchangeRates, rewards, resolver, systemSettings; let sUSDContract, sETHContract, sBTCContract; @@ -34,6 +40,7 @@ contract('TradingRewards', accounts => { const rates = { [sETH]: toUnit('100'), [sBTC]: toUnit('12000'), + [SNX]: toUnit('0.2'), }; let feesPaidUSD; @@ -94,6 +101,8 @@ contract('TradingRewards', accounts => { 'CollateralManager', ], })); + + await setupPriceAggregators(exchangeRates, owner, [sETH, sBTC]); }); before('BRRRRRR', async () => { @@ -103,14 +112,8 @@ contract('TradingRewards', accounts => { }); before('set exchange rates', async () => { - const oracle = account1; - let timestamp; for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - - await exchangeRates.updateRates([sETH, sBTC], Object.values(rates), timestamp, { - from: oracle, - }); + await updateAggregatorRates(exchangeRates, [sETH, sBTC, SNX], Object.values(rates)); } await setExchangeFeeRateForSynths({ diff --git a/test/contracts/Wrapper.js b/test/contracts/Wrapper.js index 10ca44eb9d..4247835683 100644 --- a/test/contracts/Wrapper.js +++ b/test/contracts/Wrapper.js @@ -4,12 +4,14 @@ const { contract, artifacts, web3 } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { currentTime, toUnit } = require('../utils')(); +const { toUnit } = require('../utils')(); const { ensureOnlyExpectedMutativeFunctions, getDecodedLogs, decodedEventEqual, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { setupAllContracts } = require('./setup'); @@ -23,7 +25,7 @@ contract('Wrapper', async accounts => { const ONE = toBN('1'); - const [, owner, oracle, , account1] = accounts; + const [, owner, , , account1] = accounts; let systemSettings, feePool, @@ -35,8 +37,7 @@ contract('Wrapper', async accounts => { sETHSynth, wrapperFactory, etherWrapper, - weth, - timestamp; + weth; const calculateETHToUSD = async feesInETH => { // Ask the Depot how many sUSD I will get for this ETH @@ -112,12 +113,8 @@ contract('Wrapper', async accounts => { from: owner, }); - timestamp = await currentTime(); - - // Depot requires ETH rates - await exchangeRates.updateRates([sETH, ETH], ['1500', '1500'].map(toUnit), timestamp, { - from: oracle, - }); + await setupPriceAggregators(exchangeRates, owner, [sETH, ETH]); + await updateAggregatorRates(exchangeRates, [sETH, ETH], ['1500', '1500'].map(toUnit)); }); addSnapshotBeforeRestoreAfterEach(); diff --git a/test/contracts/WrapperFactory.js b/test/contracts/WrapperFactory.js index 5fd83537bc..8c0552ebee 100644 --- a/test/contracts/WrapperFactory.js +++ b/test/contracts/WrapperFactory.js @@ -4,13 +4,15 @@ const { contract, artifacts, web3 } = require('hardhat'); const { assert, addSnapshotBeforeRestoreAfterEach } = require('./common'); -const { currentTime, toUnit } = require('../utils')(); +const { toUnit } = require('../utils')(); const { ensureOnlyExpectedMutativeFunctions, onlyGivenAddressCanInvoke, getDecodedLogs, decodedEventEqual, + setupPriceAggregators, + updateAggregatorRates, } = require('./helpers'); const { setupAllContracts } = require('./setup'); @@ -22,7 +24,7 @@ contract('WrapperFactory', async accounts => { const synths = ['sUSD', 'sETH', 'ETH', 'SNX']; const [sETH, ETH] = ['sETH', 'ETH'].map(toBytes32); - const [, owner, oracle, , account1] = accounts; + const [, owner, , , account1] = accounts; let addressResolver, flexibleStorage, @@ -32,8 +34,7 @@ contract('WrapperFactory', async accounts => { FEE_ADDRESS, sUSDSynth, wrapperFactory, - weth, - timestamp; + weth; before(async () => { ({ @@ -66,12 +67,10 @@ contract('WrapperFactory', async accounts => { })); FEE_ADDRESS = await feePool.FEE_ADDRESS(); - timestamp = await currentTime(); // Depot requires ETH rates - await exchangeRates.updateRates([sETH, ETH], ['1500', '1500'].map(toUnit), timestamp, { - from: oracle, - }); + await setupPriceAggregators(exchangeRates, owner, [sETH, ETH]); + await updateAggregatorRates(exchangeRates, [sETH, ETH], ['1500', '1500'].map(toUnit)); }); addSnapshotBeforeRestoreAfterEach(); diff --git a/test/contracts/helpers.js b/test/contracts/helpers.js index 8dac99414d..dd391cee55 100644 --- a/test/contracts/helpers.js +++ b/test/contracts/helpers.js @@ -12,6 +12,48 @@ const { constants: { ZERO_ADDRESS, ZERO_BYTES32 }, } = require('../..'); +const MockAggregator = artifacts.require('MockAggregatorV2V3'); + +/// utility function to setup price aggregators +/// @param exchangeRates instance of ExchangeRates contract +/// @param owner owner account of exchangeRates contract for adding an aggregator +/// @param keys array of bytes32 currency keys +/// @param decimalsArray optional array of ints for each key, defaults to 18 decimals +async function setupPriceAggregators(exchangeRates, owner, keys, decimalsArray = []) { + let aggregator; + for (let i = 0; i < keys.length; i++) { + aggregator = await MockAggregator.new({ from: owner }); + await aggregator.setDecimals(decimalsArray.length > 0 ? decimalsArray[i] : 18); + await exchangeRates.addAggregator(keys[i], aggregator.address, { from: owner }); + } +} + +/// same as setupPriceAggregators, but checks if an aggregator for that currency is already setup up +async function setupMissingPriceAggregators(exchangeRates, owner, keys) { + const missingKeys = []; + for (let i = 0; i < keys.length; i++) { + if ((await exchangeRates.aggregators(keys[i])) === ZERO_ADDRESS) { + missingKeys.push(keys[i]); + } + } + await setupPriceAggregators(exchangeRates, owner, missingKeys); +} +// utility function update rates for aggregators that are already set up +/// @param exchangeRates instance of ExchangeRates contract +/// @param owner owner account of exchangeRates contract for adding an aggregator +/// @param keys array of bytes32 currency keys +/// @param rates array of BN rates +/// @param timestamp optional timestamp for the update, currentTime() is used by default +async function updateAggregatorRates(exchangeRates, keys, rates, timestamp = undefined) { + timestamp = timestamp || (await currentTime()); + for (let i = 0; i < keys.length; i++) { + const aggregatorAddress = await exchangeRates.aggregators(keys[i]); + const aggregator = await MockAggregator.at(aggregatorAddress); + // set the rate + await aggregator.setLatestAnswer(rates[i], timestamp); + } +} + module.exports = { /** * the truffle transaction does not return all events logged, only those from the invoked @@ -88,31 +130,19 @@ module.exports = { return web3.utils.hexToAscii(web3.utils.utf8ToHex(input)); }, - async updateRatesWithDefaults({ exchangeRates, oracle, debtCache }) { - const [SNX, sAUD, sEUR, sBTC, iBTC, sETH, ETH] = [ - 'SNX', - 'sAUD', - 'sEUR', - 'sBTC', - 'iBTC', - 'sETH', - 'ETH', - ].map(toBytes32); - - let timestamp; + setupPriceAggregators, + + updateAggregatorRates, + + async updateRatesWithDefaults({ exchangeRates, owner, debtCache }) { + const keys = ['SNX', 'sAUD', 'sEUR', 'sBTC', 'iBTC', 'sETH', 'ETH'].map(toBytes32); + const rates = ['0.1', '0.5', '1.25', '5000', '4000', '172', '172'].map(toUnit); + // set up any missing aggregators + await setupMissingPriceAggregators(exchangeRates, owner, keys); + for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - timestamp = await currentTime(); - - await exchangeRates.updateRates( - [SNX, sAUD, sEUR, sBTC, iBTC, sETH, ETH], - ['0.1', '0.5', '1.25', '5000', '4000', '172', '172'].map(toUnit), - timestamp, - { - from: oracle, - } - ); + await updateAggregatorRates(exchangeRates, keys, rates); } - await debtCache.takeDebtSnapshot(); }, diff --git a/test/contracts/setup.js b/test/contracts/setup.js index 6f09c2f3d4..302de8ea4f 100644 --- a/test/contracts/setup.js +++ b/test/contracts/setup.js @@ -4,6 +4,8 @@ const { artifacts, web3, log } = require('hardhat'); const { toWei } = web3.utils; const { toUnit } = require('../utils')(); +const { setupPriceAggregators, updateAggregatorRates } = require('./helpers'); + const { toBytes32, getUsers, @@ -112,7 +114,7 @@ const setupContract = async ({ skipPostDeploy = false, properties = {}, }) => { - const [deployerAccount, owner, oracle, fundsWallet] = accounts; + const [deployerAccount, owner, , fundsWallet] = accounts; const artifact = artifacts.require(contract); @@ -160,20 +162,8 @@ const setupContract = async ({ AddressResolver: [owner], SystemStatus: [owner], FlexibleStorage: [tryGetAddressOf('AddressResolver')], - ExchangeRates: [ - owner, - oracle, - tryGetAddressOf('AddressResolver'), - [toBytes32('SNX')], - [toWei('0.2', 'ether')], - ], - ExchangeRatesWithDexPricing: [ - owner, - oracle, - tryGetAddressOf('AddressResolver'), - [toBytes32('SNX')], - [toWei('0.2', 'ether')], - ], + ExchangeRates: [owner, tryGetAddressOf('AddressResolver')], + ExchangeRatesWithDexPricing: [owner, tryGetAddressOf('AddressResolver')], SynthetixState: [owner, ZERO_ADDRESS], SupplySchedule: [owner, 0, 0], Proxy: [owner], @@ -1161,6 +1151,13 @@ const setupAllContracts = async ({ .map(mock => mock.setAddressResolver(returnObj['AddressResolver'].address)) ); + if (returnObj['ExchangeRates']) { + // setup SNX price feed + const SNX = toBytes32('SNX'); + await setupPriceAggregators(returnObj['ExchangeRates'], owner, [SNX]); + await updateAggregatorRates(returnObj['ExchangeRates'], [SNX], [toUnit('0.2')]); + } + return returnObj; }; diff --git a/test/integration/behaviors/exchange.behavior.js b/test/integration/behaviors/exchange.behavior.js index 6bf8d62eae..2437fe97eb 100644 --- a/test/integration/behaviors/exchange.behavior.js +++ b/test/integration/behaviors/exchange.behavior.js @@ -41,7 +41,8 @@ function itCanExchange({ ctx }) { await updateCache({ ctx }); const tx = await Synthetix.exchange(toBytes32('sUSD'), sUSDAmount, toBytes32('sETH')); - await tx.wait(); + const { gasUsed } = await tx.wait(); + console.log(`exchange() gas used: ${Math.round(gasUsed / 1000).toString()}k`); }); it('receives the expected amount of sETH', async () => { @@ -77,7 +78,8 @@ function itCanExchange({ ctx }) { before('settle', async () => { const tx = await Synthetix.settle(toBytes32('sETH')); - await tx.wait(); + const { gasUsed } = await tx.wait(); + console.log(`settle() gas used: ${Math.round(gasUsed / 1000).toString()}k`); }); it('shows that the user no longer has pending settlements', async () => { diff --git a/test/integration/behaviors/redeem.behavior.js b/test/integration/behaviors/redeem.behavior.js index 7b1d5f793b..4e855ce62c 100644 --- a/test/integration/behaviors/redeem.behavior.js +++ b/test/integration/behaviors/redeem.behavior.js @@ -6,7 +6,7 @@ const { } = require('../../../index'); const { ensureBalance } = require('../utils/balances'); const { skipWaitingPeriod } = require('../utils/skip'); -const { updateExchangeRatesIfNeeded } = require('../utils/rates'); +const { increaseStalePeriodAndCheckRatesAndCache } = require('../utils/rates'); function itCanRedeem({ ctx }) { describe('redemption of deprecated synths', () => { @@ -57,7 +57,7 @@ function itCanRedeem({ ctx }) { }); before('update rates and take snapshot if needed', async () => { - await updateExchangeRatesIfNeeded({ ctx }); + await increaseStalePeriodAndCheckRatesAndCache({ ctx }); }); before('record total system debt', async () => { diff --git a/test/integration/behaviors/stake.behavior.js b/test/integration/behaviors/stake.behavior.js index cf886c5bdc..4f0b608fe7 100644 --- a/test/integration/behaviors/stake.behavior.js +++ b/test/integration/behaviors/stake.behavior.js @@ -33,7 +33,8 @@ function itCanStake({ ctx }) { Synthetix = Synthetix.connect(user); const tx = await Synthetix.issueSynths(amountToIssueAndBurnsUSD); - await tx.wait(); + const { gasUsed } = await tx.wait(); + console.log(`issueSynths() gas used: ${Math.round(gasUsed / 1000).toString()}k`); }); it('issues the expected amount of sUSD', async () => { @@ -69,7 +70,8 @@ function itCanStake({ ctx }) { FeePool = FeePool.connect(user); const tx = await FeePool.claimFees(); - await tx.wait(); + const { gasUsed } = await tx.wait(); + console.log(`claimFees() gas used: ${Math.round(gasUsed / 1000).toString()}k`); }); it('shows a slight increase in the users sUSD balance', async () => { @@ -93,7 +95,8 @@ function itCanStake({ ctx }) { Synthetix = Synthetix.connect(user); const tx = await Synthetix.burnSynths(amountToIssueAndBurnsUSD); - await tx.wait(); + const { gasUsed } = await tx.wait(); + console.log(`burnSynths() gas used: ${Math.round(gasUsed / 1000).toString()}k`); }); it('reduced the expected amount of debt', async () => { diff --git a/test/integration/utils/bootstrap.js b/test/integration/utils/bootstrap.js index 0060f92781..c905e731e5 100644 --- a/test/integration/utils/bootstrap.js +++ b/test/integration/utils/bootstrap.js @@ -2,7 +2,7 @@ const hre = require('hardhat'); const ethers = require('ethers'); const { loadUsers } = require('./users'); const { connectContracts } = require('./contracts'); -const { updateExchangeRatesIfNeeded } = require('./rates'); +const { increaseStalePeriodAndCheckRatesAndCache } = require('./rates'); const { ensureBalance } = require('./balances'); const { setupOptimismWatchers, approveBridge } = require('./optimism'); const { startOpsHeartbeat } = require('./optimism-temp'); @@ -26,7 +26,7 @@ function bootstrapL1({ ctx }) { connectContracts({ ctx }); - await updateExchangeRatesIfNeeded({ ctx }); + await increaseStalePeriodAndCheckRatesAndCache({ ctx }); }); } @@ -57,7 +57,7 @@ function bootstrapL2({ ctx }) { connectContracts({ ctx }); - await updateExchangeRatesIfNeeded({ ctx }); + await increaseStalePeriodAndCheckRatesAndCache({ ctx }); await ensureBalance({ ctx, @@ -95,8 +95,8 @@ function bootstrapDual({ ctx }) { connectContracts({ ctx: ctx.l1 }); connectContracts({ ctx: ctx.l2 }); - await updateExchangeRatesIfNeeded({ ctx: ctx.l1 }); - await updateExchangeRatesIfNeeded({ ctx: ctx.l2 }); + await increaseStalePeriodAndCheckRatesAndCache({ ctx: ctx.l1 }); + await increaseStalePeriodAndCheckRatesAndCache({ ctx: ctx.l2 }); await approveBridge({ ctx: ctx.l1, amount: ethers.utils.parseEther('100000000') }); diff --git a/test/integration/utils/rates.js b/test/integration/utils/rates.js index 09de49582e..f5bc6ba8dd 100644 --- a/test/integration/utils/rates.js +++ b/test/integration/utils/rates.js @@ -4,15 +4,18 @@ const { toBytes32, defaults: { EXCHANGE_DYNAMIC_FEE_ROUNDS }, } = require('../../..'); +const { createMockAggregatorFactory } = require('../../utils')(); -async function updateExchangeRatesIfNeeded({ ctx }) { +async function increaseStalePeriodAndCheckRatesAndCache({ ctx }) { await setSystemSetting({ ctx, settingName: 'rateStalePeriod', newValue: '1000000000' }); if (await _areRatesInvalid({ ctx })) { - await _setNewRates({ ctx }); + // try to add the missing rates + await _setMissingRates({ ctx }); + // check again if (await _areRatesInvalid({ ctx })) { await _printRatesInfo({ ctx }); - throw new Error('Rates are still invalid after updating them.'); + throw new Error('Rates are still invalid after updating.'); } } @@ -74,36 +77,41 @@ async function _getAvailableCurrencyKeys({ ctx }) { .concat(['SNX', 'ETH'].map(toBytes32)); } -async function _getCurrentRates({ ctx, currencyKeys }) { - const { ExchangeRates } = ctx.contracts; - - const rates = []; - for (const currencyKey of currencyKeys) { - const rate = await ExchangeRates.rateForCurrency(currencyKey); - - // Simualte any exchange rates that are 0. - const newRate = rate.toString() === '0' ? ethers.utils.parseEther('1') : rate; - - rates.push(newRate); +async function _setMissingRates({ ctx }) { + let currencyKeys; + if (ctx.fork) { + // this adds a rate for only e.g. sREDEEMER in fork mode (which is not an existing synth + // but is added to test the redeeming functionality) + // All other synths should have feeds in fork mode + currencyKeys = (ctx.addedSynths || []).map(o => toBytes32(o.name)); + } else { + // set missing rates for all synths, since not in fork mode we don't have existing feeds + currencyKeys = await _getAvailableCurrencyKeys({ ctx }); } - return rates; -} - -async function _setNewRates({ ctx }) { - let { ExchangeRates } = ctx.contracts; - const oracle = await ExchangeRates.oracle(); - const signer = ctx.fork ? ctx.provider.getSigner(oracle) : ctx.users.owner; - ExchangeRates = ExchangeRates.connect(signer); + const owner = ctx.users.owner; + const ExchangeRates = ctx.contracts.ExchangeRates.connect(owner); - const currencyKeys = await _getAvailableCurrencyKeys({ ctx }); - const rates = await _getCurrentRates({ ctx, currencyKeys }); + // factory for price aggregators contracts + const MockAggregatorFactory = await createMockAggregatorFactory(owner); + // got over all rates and add aggregators + const { timestamp } = await ctx.provider.getBlock(); for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - const { timestamp } = await ctx.provider.getBlock(); - - const tx = await ExchangeRates.updateRates(currencyKeys, rates, timestamp); - await tx.wait(); + for (const currencyKey of currencyKeys) { + const rate = await ExchangeRates.rateForCurrency(currencyKey); + if (rate.toString() === '0') { + // deploy an aggregator + let aggregator = await MockAggregatorFactory.deploy(); + aggregator = aggregator.connect(owner); + // set decimals + await (await aggregator.setDecimals(18)).wait(); + // push the new price + await (await aggregator.setLatestAnswer(ethers.utils.parseEther('1'), timestamp)).wait(); + // set the aggregator in ExchangeRates + await (await ExchangeRates.addAggregator(currencyKey, aggregator.address)).wait(); + } + } } } @@ -127,7 +135,7 @@ async function getRate({ ctx, symbol }) { } module.exports = { - updateExchangeRatesIfNeeded, + increaseStalePeriodAndCheckRatesAndCache, getRate, updateCache, }; diff --git a/test/integration/utils/skip.js b/test/integration/utils/skip.js index b32ce985ce..f668acff22 100644 --- a/test/integration/utils/skip.js +++ b/test/integration/utils/skip.js @@ -1,7 +1,7 @@ const { fastForward } = require('../../test-utils/rpc'); const { wait } = require('../../test-utils/wait'); const { getSystemSetting } = require('./settings'); -const { updateExchangeRatesIfNeeded } = require('./rates'); +const { increaseStalePeriodAndCheckRatesAndCache } = require('./rates'); async function skipWaitingPeriod({ ctx }) { await _dualFastForward({ @@ -35,7 +35,7 @@ async function _dualFastForward({ ctx, seconds }) { await fastForward({ seconds: parseInt(seconds), provider: l1Ctx.provider }); await wait({ seconds: 6 }); - await updateExchangeRatesIfNeeded({ ctx }); + await increaseStalePeriodAndCheckRatesAndCache({ ctx }); } module.exports = { diff --git a/test/publish/index.js b/test/publish/index.js index 798992bac8..318eaf80df 100644 --- a/test/publish/index.js +++ b/test/publish/index.js @@ -6,14 +6,12 @@ const pLimit = require('p-limit'); const ethers = require('ethers'); const isCI = require('is-ci'); -const { loadCompiledFiles } = require('../../publish/src/solidity'); const { loadLocalWallets } = require('../test-utils/wallets'); const { fastForward } = require('../test-utils/rpc'); const deployStakingRewardsCmd = require('../../publish/src/commands/deploy-staking-rewards'); const deployShortingRewardsCmd = require('../../publish/src/commands/deploy-shorting-rewards'); const deployCmd = require('../../publish/src/commands/deploy'); -const { buildPath } = deployCmd.DEFAULTS; const testUtils = require('../utils'); const commands = { @@ -97,6 +95,7 @@ describe('publish scripts', () => { let sETH; let provider; let overrides; + let MockAggregatorFactory; const resetConfigAndSynthFiles = () => { // restore the synths and config files for this env (cause removal updated it) @@ -135,7 +134,7 @@ describe('publish scripts', () => { url: 'http://localhost:8545', }); - const { isCompileRequired } = testUtils(); + const { isCompileRequired, createMockAggregatorFactory } = testUtils(); // load accounts used by local EVM const wallets = loadLocalWallets({ provider }); @@ -154,6 +153,8 @@ describe('publish scripts', () => { console.log('Skipping build as everything up to date'); } + MockAggregatorFactory = await createMockAggregatorFactory(accounts.deployer); + [sUSD, sBTC, sETH] = ['sUSD', 'sBTC', 'sETH'].map(toBytes32); gasLimit = 8000000; @@ -195,15 +196,6 @@ describe('publish scripts', () => { ); const createMockAggregator = async () => { - // get last build - const { compiled } = loadCompiledFiles({ buildPath }); - const { - abi, - evm: { - bytecode: { object: bytecode }, - }, - } = compiled['MockAggregatorV2V3']; - const MockAggregatorFactory = new ethers.ContractFactory(abi, bytecode, accounts.deployer); const MockAggregator = await MockAggregatorFactory.deploy({ gasLimit, gasPrice }); const tx = await MockAggregator.setDecimals('8', { diff --git a/test/utils/index.js b/test/utils/index.js index c83711eedf..fcad276337 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -528,6 +528,18 @@ module.exports = ({ web3 } = {}) => { return latestSolTimestamp > earliestCompiledTimestamp; }; + // create a factory to deploy mock price aggregators + const createMockAggregatorFactory = async account => { + const { compiled } = loadCompiledFiles({ buildPath }); + const { + abi, + evm: { + bytecode: { object: bytecode }, + }, + } = compiled['MockAggregatorV2V3']; + return new ethers.ContractFactory(abi, bytecode, account); + }; + const setupProvider = ({ providerUrl, privateKey, publicKey }) => { const provider = new ethers.providers.JsonRpcProvider(providerUrl); @@ -606,6 +618,7 @@ module.exports = ({ web3 } = {}) => { loadLocalUsers, isCompileRequired, + createMockAggregatorFactory, setupProvider, getContract, From 955b5b1dc4e503bc56573eceffd22a918eddfb21 Mon Sep 17 00:00:00 2001 From: Lecky Date: Sat, 25 Dec 2021 22:14:05 +1100 Subject: [PATCH 02/11] fix ExchangeRates test - apply AtRound changes - Adding cacheRates on ExchangeRates --- contracts/ExchangeRates.sol | 73 ++++++++++++++--- contracts/Exchanger.sol | 101 ++++++++++++++++++++++-- contracts/interfaces/IExchangeRates.sol | 2 + test/contracts/ExchangeRates.js | 16 ++-- 4 files changed, 167 insertions(+), 25 deletions(-) diff --git a/contracts/ExchangeRates.sol b/contracts/ExchangeRates.sol index c3bae1220c..a9bf7aa027 100644 --- a/contracts/ExchangeRates.sol +++ b/contracts/ExchangeRates.sol @@ -22,8 +22,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { using SafeDecimalMath for uint; bytes32 public constant CONTRACT_NAME = "ExchangeRates"; - //slither-disable-next-line naming-convention - bytes32 internal constant sUSD = "sUSD"; + bytes32 internal constant SUSD = "sUSD"; // Decentralized oracle networks that feed into pricing aggregators mapping(bytes32 => AggregatorV2V3Interface) public aggregators; @@ -33,6 +32,8 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { // List of aggregator keys for convenient iteration bytes32[] public aggregatorKeys; + mapping(bytes32 => mapping(uint => RateAndUpdatedTime)) public cacheRates; + // ========== CONSTRUCTOR ========== constructor(address _owner, address _resolver) public Owned(_owner) MixinSystemSettings(_resolver) {} @@ -96,7 +97,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { uint time; (sourceRate, time) = _getRateAndTimestampAtRound(sourceCurrencyKey, roundIdForSrc); // cacheing to save external call - _setRate(sourceCurrencyKey, roundIdForSrc, sourceRate, time); + _setCacheRate(sourceCurrencyKey, roundIdForSrc, sourceRate, time); // If there's no change in the currency, then just return the amount they gave us if (sourceCurrencyKey == destinationCurrencyKey) { destinationRate = sourceRate; @@ -104,7 +105,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { } else { (destinationRate, time) = _getRateAndTimestampAtRound(destinationCurrencyKey, roundIdForDest); // cacheing to save external call - _setRate(destinationCurrencyKey, roundIdForDest, destinationRate, time); + _setCacheRate(destinationCurrencyKey, roundIdForDest, destinationRate, time); // prevent divide-by 0 error (this happens if the dest is not a valid rate) if (destinationRate > 0) { // Calculate the effective value by going from source -> USD -> destination @@ -113,6 +114,17 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { } } + function _setCacheRate( + bytes32 currencyKey, + uint roundId, + uint rate, + uint time + ) internal { + if (rate > 0) { + cacheRates[currencyKey][roundId] = RateAndUpdatedTime({rate: uint216(rate), time: uint40(time)}); + } + } + /* ========== VIEWS ========== */ function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory currencies) { @@ -288,7 +300,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid) { RateAndUpdatedTime memory rateAndTime = _getRateAndUpdatedTime(currencyKey); - if (currencyKey == sUSD) { + if (currencyKey == SUSD) { return (rateAndTime.rate, false); } return ( @@ -314,7 +326,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { // do one lookup of the rate & time to minimize gas RateAndUpdatedTime memory rateEntry = _getRateAndUpdatedTime(currencyKeys[i]); rates[i] = rateEntry.rate; - if (!anyRateInvalid && currencyKeys[i] != sUSD) { + if (!anyRateInvalid && currencyKeys[i] != SUSD) { anyRateInvalid = flagList[i] || _rateIsStaleWithTime(_rateStalePeriod, rateEntry.time); } } @@ -349,6 +361,27 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { return false; } + function anyRateIsInvalidAtRound(bytes32[] calldata currencyKeys, uint[] calldata roundIds) + external + view + returns (bool) + { + // Loop through each key and check whether the data point is stale. + + require(roundIds.length == currencyKeys.length, "roundIds must be the same length as currencyKeys"); + + uint256 _rateStalePeriod = getRateStalePeriod(); + bool[] memory flagList = getFlagsForRates(currencyKeys); + + for (uint i = 0; i < currencyKeys.length; i++) { + if (flagList[i] || _rateIsStaleAtRound(currencyKeys[i], roundIds[i], _rateStalePeriod)) { + return true; + } + } + + return false; + } + function synthTooVolatileForAtomicExchange(bytes32) external view returns (bool) { _notImplemented(); } @@ -402,7 +435,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function _getRateAndUpdatedTime(bytes32 currencyKey) internal view returns (RateAndUpdatedTime memory) { // sUSD rate is 1.0 - if (currencyKey == sUSD) { + if (currencyKey == SUSD) { return RateAndUpdatedTime({rate: uint216(SafeDecimalMath.unit()), time: 0}); } else { AggregatorV2V3Interface aggregator = aggregators[currencyKey]; @@ -428,7 +461,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { } function _getCurrentRoundId(bytes32 currencyKey) internal view returns (uint) { - if (currencyKey == sUSD) { + if (currencyKey == SUSD) { return 0; // no roundIds for sUSD } AggregatorV2V3Interface aggregator = aggregators[currencyKey]; @@ -439,11 +472,17 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function _getRateAndTimestampAtRound(bytes32 currencyKey, uint roundId) internal view returns (uint rate, uint time) { // short circuit sUSD - if (currencyKey == sUSD) { + if (currencyKey == SUSD) { // sUSD has no rounds, and 0 time is preferrable for "volatility" heuristics // which are used in atomic swaps and fee reclamation return (SafeDecimalMath.unit(), 0); } else { + if (cacheRates[currencyKey][roundId].rate != 0) { + return ( + _formatAggregatorAnswer(currencyKey, cacheRates[currencyKey][roundId].rate), + cacheRates[currencyKey][roundId].time + ); + } AggregatorV2V3Interface aggregator = aggregators[currencyKey]; if (aggregator != AggregatorV2V3Interface(0)) { @@ -500,18 +539,30 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function _rateIsStale(bytes32 currencyKey, uint _rateStalePeriod) internal view returns (bool) { // sUSD is a special case and is never stale (check before an SLOAD of getRateAndUpdatedTime) - if (currencyKey == sUSD) return false; + if (currencyKey == SUSD) return false; return _rateIsStaleWithTime(_rateStalePeriod, _getUpdatedTime(currencyKey)); } + function _rateIsStaleAtRound( + bytes32 currencyKey, + uint roundId, + uint _rateStalePeriod + ) internal view returns (bool) { + // sUSD is a special case and is never stale (check before an SLOAD of getRateAndUpdatedTime) + if (currencyKey == SUSD) return false; + + (, uint time) = _getRateAndTimestampAtRound(currencyKey, roundId); + return _rateIsStaleWithTime(_rateStalePeriod, time); + } + function _rateIsStaleWithTime(uint _rateStalePeriod, uint _time) internal view returns (bool) { return _time.add(_rateStalePeriod) < now; } function _rateIsFlagged(bytes32 currencyKey, FlagsInterface flags) internal view returns (bool) { // sUSD is a special case and is never invalid - if (currencyKey == sUSD) return false; + if (currencyKey == SUSD) return false; address aggregator = address(aggregators[currencyKey]); // when no aggregator or when the flags haven't been setup if (aggregator == address(0) || flags == FlagsInterface(0)) { diff --git a/contracts/Exchanger.sol b/contracts/Exchanger.sol index 6f308e219f..aa2787f964 100644 --- a/contracts/Exchanger.sol +++ b/contracts/Exchanger.sol @@ -451,7 +451,13 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger { entry.roundIdForDest ); - _ensureCanExchange(sourceCurrencyKey, sourceAmount, destinationCurrencyKey); + _ensureCanExchangeAtRound( + sourceCurrencyKey, + sourceAmount, + destinationCurrencyKey, + entry.roundIdForSrc, + entry.roundIdForDest + ); // SIP-65: Decentralized Circuit Breaker // mutative call to suspend system if the rate is invalid @@ -470,7 +476,12 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger { return (0, 0, IVirtualSynth(0)); } - entry.exchangeFeeRate = _feeRateForExchange(sourceCurrencyKey, destinationCurrencyKey); + entry.exchangeFeeRate = _feeRateForExchangeAtRound( + sourceCurrencyKey, + destinationCurrencyKey, + entry.roundIdForSrc, + entry.roundIdForDest + ); amountReceived = _deductFeesFromAmount(entry.destinationAmount, entry.exchangeFeeRate); // Note: `fee` is denominated in the destinationCurrencyKey. @@ -620,6 +631,26 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger { require(!exchangeRates().anyRateIsInvalid(synthKeys), "Src/dest rate invalid or not found"); } + function _ensureCanExchangeAtRound( + bytes32 sourceCurrencyKey, + uint sourceAmount, + bytes32 destinationCurrencyKey, + uint roundIdForSrc, + uint roundIdForDest + ) 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; + + uint[] memory roundIds = new uint[](2); + roundIds[0] = roundIdForSrc; + roundIds[1] = roundIdForDest; + require(!exchangeRates().anyRateIsInvalidAtRound(synthKeys, roundIds), "Src/dest rate invalid or not found"); + } + function _isSynthRateInvalid(bytes32 currencyKey, uint currentRate) internal view returns (bool) { if (currentRate == 0) { return true; @@ -771,6 +802,31 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger { return _calculateFeeRateFromExchangeSynths(baseRate, 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 + /// @param roundIdForSrc The round id of the source currency. + /// @param roundIdForDest The round id of the target currency. + /// @return The exchange fee rate + /// @return The exchange dynamic fee rate + function _feeRateForExchangeAtRound( + bytes32 sourceCurrencyKey, + bytes32 destinationCurrencyKey, + uint roundIdForSrc, + uint roundIdForDest + ) internal view returns (uint exchangeFeeRate) { + // Get the exchange fee rate as per destination currencyKey + uint baseRate = getExchangeFeeRate(destinationCurrencyKey); + return + _calculateFeeRateFromExchangeSynthsAtRound( + baseRate, + sourceCurrencyKey, + destinationCurrencyKey, + roundIdForSrc, + roundIdForDest + ); + } + function _calculateFeeRateFromExchangeSynths( uint exchangeFeeRate, bytes32 sourceCurrencyKey, @@ -786,19 +842,48 @@ contract Exchanger is Owned, MixinSystemSettings, IExchanger { return exchangeFeeRate; } + function _calculateFeeRateFromExchangeSynthsAtRound( + uint exchangeFeeRate, + bytes32 sourceCurrencyKey, + bytes32 destinationCurrencyKey, + uint roundIdForSrc, + uint roundIdForDest + ) internal view returns (uint) { + uint exchangeDynamicFeeRate = _getDynamicFeeForExchangeAtRound(destinationCurrencyKey, roundIdForDest); + exchangeDynamicFeeRate = exchangeDynamicFeeRate.add( + _getDynamicFeeForExchangeAtRound(sourceCurrencyKey, roundIdForSrc) + ); + uint maxDynamicFee = getExchangeMaxDynamicFee(); + + exchangeFeeRate = exchangeFeeRate.add(exchangeDynamicFeeRate); + // Cap to max exchange dynamic fee + exchangeFeeRate = exchangeFeeRate > maxDynamicFee ? maxDynamicFee : exchangeFeeRate; + return exchangeFeeRate; + } + /// @notice Get dynamic fee for a given currency key (SIP-184) /// @param currencyKey The given currency key /// @return The dyanmic fee function _getDynamicFeeForExchange(bytes32 currencyKey) internal view returns (uint dynamicFee) { // No dynamic fee for sUSD - if (currencyKey == sUSD) { - return 0; - } + if (currencyKey == sUSD) return 0; + (uint threshold, uint weightDecay, uint rounds) = getExchangeDynamicFeeData(); + uint[] memory prices; + uint roundId = exchangeRates().getCurrentRoundId(currencyKey); + (prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, rounds, roundId); + dynamicFee = DynamicFee.getDynamicFee(prices, threshold, weightDecay); + } + + /// @notice Get dynamic fee for a given currency key (SIP-184) + /// @param currencyKey The given currency key + /// @param roundId The round id + /// @return The dyanmic fee + function _getDynamicFeeForExchangeAtRound(bytes32 currencyKey, uint roundId) internal view returns (uint dynamicFee) { + // No dynamic fee for sUSD + if (currencyKey == sUSD) return 0; (uint threshold, uint weightDecay, uint rounds) = getExchangeDynamicFeeData(); uint[] memory prices; - // Note: We are using cache round ID here for cheap read - uint currentRoundId = exchangeRates().currentRoundForRate(currencyKey); - (prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, rounds, currentRoundId); + (prices, ) = exchangeRates().ratesAndUpdatedTimeForCurrencyLastNRounds(currencyKey, rounds, roundId); dynamicFee = DynamicFee.getDynamicFee(prices, threshold, weightDecay); } diff --git a/contracts/interfaces/IExchangeRates.sol b/contracts/interfaces/IExchangeRates.sol index f1110010c8..bcc6501956 100644 --- a/contracts/interfaces/IExchangeRates.sol +++ b/contracts/interfaces/IExchangeRates.sol @@ -15,6 +15,8 @@ interface IExchangeRates { function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool); + function anyRateIsInvalidAtRound(bytes32[] calldata currencyKeys, uint[] calldata roundIds) external view returns (bool); + function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory); function effectiveValue( diff --git a/test/contracts/ExchangeRates.js b/test/contracts/ExchangeRates.js index c5a78a4cfb..1d65f54832 100644 --- a/test/contracts/ExchangeRates.js +++ b/test/contracts/ExchangeRates.js @@ -55,7 +55,11 @@ contract('Exchange Rates', async accounts => { let mockFlagsInterface; const itIncludesCorrectMutativeFunctions = contract => { - const baseFunctions = ['addAggregator', 'removeAggregator']; + const baseFunctions = [ + 'addAggregator', + 'removeAggregator', + 'mutativeEffectiveValueAndRatesAtRound', + ]; const withDexPricingFunctions = baseFunctions.concat(['setDexPriceAggregator']); it('only expected functions should be mutative', () => { @@ -949,7 +953,7 @@ contract('Exchange Rates', async accounts => { }); it('ratesAndUpdatedTimeForCurrencyLastNRounds() shows first entry for sUSD', async () => { - assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sUSD, '3'), [ + assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sUSD, '3', '0'), [ [toUnit('1'), '0', '0'], [0, 0, 0], ]); @@ -957,7 +961,7 @@ contract('Exchange Rates', async accounts => { it('ratesAndUpdatedTimeForCurrencyLastNRounds() returns 0s for other currencies without updates', async () => { const fiveZeros = new Array(5).fill('0'); await setupAggregators([sJPY]); - assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '5'), [ + assert.deepEqual(await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '5', '0'), [ fiveZeros, fiveZeros, ]); @@ -1012,7 +1016,7 @@ contract('Exchange Rates', async accounts => { it('then it returns zeros', async () => { const fiveZeros = new Array(5).fill('0'); assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sAUD, '5'), + await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sAUD, '5', '0'), [fiveZeros, fiveZeros] ); }); @@ -1020,7 +1024,7 @@ contract('Exchange Rates', async accounts => { describe('when invoked for an aggregated price', () => { it('then it returns the rates as expected', async () => { assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '3'), + await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '3', '0'), [ [toUnit('102'), toUnit('101'), toUnit('100')], ['1002', '1001', '1000'], @@ -1030,7 +1034,7 @@ contract('Exchange Rates', async accounts => { it('then it returns the rates as expected, even over the edge', async () => { assert.deepEqual( - await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '5'), + await instance.ratesAndUpdatedTimeForCurrencyLastNRounds(sJPY, '5', '0'), [ [toUnit('102'), toUnit('101'), toUnit('100'), '0', '0'], ['1002', '1001', '1000', '0', '0'], From feb03f0509da303e4b74a19f174a4f6a577780d3 Mon Sep 17 00:00:00 2001 From: Lecky Date: Sun, 26 Dec 2021 11:14:48 +1100 Subject: [PATCH 03/11] fixing ExchangerWithFeeRecAlternatives.unit.js - Adding anyRateIsInvalidAtRound mock --- .../ExchangerWithFeeRecAlternatives.behaviors.js | 8 ++++++++ test/contracts/ExchangerWithFeeRecAlternatives.unit.js | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/test/contracts/ExchangerWithFeeRecAlternatives.behaviors.js b/test/contracts/ExchangerWithFeeRecAlternatives.behaviors.js index a952f77fea..ff93158feb 100644 --- a/test/contracts/ExchangerWithFeeRecAlternatives.behaviors.js +++ b/test/contracts/ExchangerWithFeeRecAlternatives.behaviors.js @@ -113,6 +113,14 @@ module.exports = function({ accounts }) { cb(); }); }, + whenMockedWithExchangeRatesValidityAtRound: ({ valid = true }, cb) => { + describe(`when mocked with ${valid ? 'valid' : 'invalid'} exchange rates`, () => { + beforeEach(async () => { + this.mocks.ExchangeRates.smocked.anyRateIsInvalidAtRound.will.return.with(!valid); + }); + cb(); + }); + }, whenMockedWithNoPriorExchangesToSettle: cb => { describe(`when mocked with no prior exchanges to settle`, () => { beforeEach(async () => { diff --git a/test/contracts/ExchangerWithFeeRecAlternatives.unit.js b/test/contracts/ExchangerWithFeeRecAlternatives.unit.js index d8577c3509..c507886df0 100644 --- a/test/contracts/ExchangerWithFeeRecAlternatives.unit.js +++ b/test/contracts/ExchangerWithFeeRecAlternatives.unit.js @@ -247,7 +247,7 @@ contract('ExchangerWithFeeRecAlternatives (unit tests)', async accounts => { }; describe('failure modes', () => { - behaviors.whenMockedWithExchangeRatesValidity({ valid: false }, () => { + behaviors.whenMockedWithExchangeRatesValidityAtRound({ valid: false }, () => { it('reverts when either rate is invalid', async () => { await assert.revert( this.instance.exchange(...getExchangeArgs()), From 35a4a7b9e9eafa75c05d6e7dede31afe1900813f Mon Sep 17 00:00:00 2001 From: Lecky Date: Sun, 2 Jan 2022 18:03:29 +1100 Subject: [PATCH 04/11] Fix RewardsIntegrationTests.js - Add updateRatesWithDefaults to invoid invalid rate --- test/contracts/RewardsIntegrationTests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/contracts/RewardsIntegrationTests.js b/test/contracts/RewardsIntegrationTests.js index f50af7f70c..dcb090d0a2 100644 --- a/test/contracts/RewardsIntegrationTests.js +++ b/test/contracts/RewardsIntegrationTests.js @@ -559,8 +559,8 @@ contract('Rewards Integration Tests', accounts => { assert.bnClose(account3Rewards[1], rewardsAmount, '1'); // Accounts 2 & 3 claim + await updateRatesWithDefaults({ exchangeRates, owner, debtCache }); await feePool.claimFees({ from: account2 }); - // updateRatesWithDefaults(); await feePool.claimFees({ from: account3 }); // Accounts 2 & 3 now have the rewards escrowed From d904b7ac34c913653a7e3a298a832cf7f9590a36 Mon Sep 17 00:00:00 2001 From: Lecky Date: Tue, 4 Jan 2022 14:09:49 +1100 Subject: [PATCH 05/11] Fix Exchanger.spec.js - move setPriceAggregator out of the updateRates loop --- test/contracts/Exchanger.spec.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/contracts/Exchanger.spec.js b/test/contracts/Exchanger.spec.js index 5a6f7c5000..282c71e66e 100644 --- a/test/contracts/Exchanger.spec.js +++ b/test/contracts/Exchanger.spec.js @@ -3507,10 +3507,10 @@ contract('Exchanger (spec tests)', async accounts => { addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { + const keys = [sAUD, sEUR, SNX, sETH, sBTC, iBTC]; + const rates = ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit); + await setupPriceAggregators(exchangeRates, owner, keys); for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - const keys = [sAUD, sEUR, SNX, sETH, sBTC, iBTC]; - const rates = ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit); - await setupPriceAggregators(exchangeRates, owner, keys); await updateRates(keys, rates); } @@ -3605,10 +3605,10 @@ contract('Exchanger (spec tests)', async accounts => { addSnapshotBeforeRestoreAfterEach(); beforeEach(async () => { + const keys = [sAUD, sEUR, SNX, sETH, sBTC, iBTC]; + const rates = ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit); + await setupPriceAggregators(exchangeRates, owner, keys); for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - const keys = [sAUD, sEUR, SNX, sETH, sBTC, iBTC]; - const rates = ['0.5', '2', '1', '100', '5000', '5000'].map(toUnit); - await setupPriceAggregators(exchangeRates, owner, keys); await updateRates(keys, rates); } From 1d1ef57cb189986baa9bb1ccb2efd4b50d200f62 Mon Sep 17 00:00:00 2001 From: Lecky Date: Tue, 4 Jan 2022 22:15:01 +1100 Subject: [PATCH 06/11] Fix Exchanger.spec.js - Fix set price with no volatility on exchangeAtomically --- test/contracts/Exchanger.spec.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/test/contracts/Exchanger.spec.js b/test/contracts/Exchanger.spec.js index 282c71e66e..24c6d36c6d 100644 --- a/test/contracts/Exchanger.spec.js +++ b/test/contracts/Exchanger.spec.js @@ -2494,15 +2494,9 @@ contract('Exchanger (spec tests)', async accounts => { const aggregator = await MockAggregator.new({ from: owner }); await exchangeRates.addAggregator(sETH, aggregator.address, { from: owner }); // set prices with no volatility - // Need to start from round 11 as the first 10 rounds are used for the setup - await aggregator.setLatestAnswerWithRound( - ethOnCL, - (await currentTime()) - 20 * 60, - '11' - ); - await aggregator.setLatestAnswer(ethOnCL, (await currentTime()) - 15 * 60); - await aggregator.setLatestAnswer(ethOnCL, (await currentTime()) - 10 * 60); - await aggregator.setLatestAnswer(ethOnCL, (await currentTime()) - 5 * 60); + for (let i = EXCHANGE_DYNAMIC_FEE_ROUNDS; i > 0; i--) { + await aggregator.setLatestAnswer(ethOnCL, (await currentTime()) - i * 5 * 60); + } // DexPriceAggregator const dexPriceAggregator = await MockDexPriceAggregator.new(); From b59918762cad241038371fa23f0ace06ac52e8ad Mon Sep 17 00:00:00 2001 From: Lecky Date: Thu, 6 Jan 2022 11:42:56 +1100 Subject: [PATCH 07/11] Fix test/publish - remove format from cacheRate as it's already been formatted --- contracts/ExchangeRates.sol | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/contracts/ExchangeRates.sol b/contracts/ExchangeRates.sol index a9bf7aa027..bf18a05762 100644 --- a/contracts/ExchangeRates.sol +++ b/contracts/ExchangeRates.sol @@ -478,10 +478,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { return (SafeDecimalMath.unit(), 0); } else { if (cacheRates[currencyKey][roundId].rate != 0) { - return ( - _formatAggregatorAnswer(currencyKey, cacheRates[currencyKey][roundId].rate), - cacheRates[currencyKey][roundId].time - ); + return (cacheRates[currencyKey][roundId].rate, cacheRates[currencyKey][roundId].time); } AggregatorV2V3Interface aggregator = aggregators[currencyKey]; From d41d2160de646b33f3b3f8f79f18e4ac409e305d Mon Sep 17 00:00:00 2001 From: Lecky Date: Thu, 6 Jan 2022 13:28:57 +1100 Subject: [PATCH 08/11] Using roundId 1 as last round to be consistent --- contracts/ExchangeRates.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/ExchangeRates.sol b/contracts/ExchangeRates.sol index bf18a05762..044317170d 100644 --- a/contracts/ExchangeRates.sol +++ b/contracts/ExchangeRates.sol @@ -278,7 +278,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { // regardless of current rate (rates[i], times[i]) = _getRateAndTimestampAtRound(currencyKey, roundId); - if (roundId == 0) { + if (roundId == 1) { // if we hit the last round, then return what we have return (rates, times); } else { @@ -462,7 +462,7 @@ contract ExchangeRates is Owned, MixinSystemSettings, IExchangeRates { function _getCurrentRoundId(bytes32 currencyKey) internal view returns (uint) { if (currencyKey == SUSD) { - return 0; // no roundIds for sUSD + return 1; // consistent with ChainLink Oracle that start at round 1 } AggregatorV2V3Interface aggregator = aggregators[currencyKey]; if (aggregator != AggregatorV2V3Interface(0)) { From 2b4bd7349ebe2182b22d12d7ad60b6bd33570b01 Mon Sep 17 00:00:00 2001 From: Lecky Date: Thu, 6 Jan 2022 13:59:44 +1100 Subject: [PATCH 09/11] Fix integration test - Having the rounds rate loop inside the aggregator --- test/integration/utils/rates.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/integration/utils/rates.js b/test/integration/utils/rates.js index f5bc6ba8dd..e40690ad79 100644 --- a/test/integration/utils/rates.js +++ b/test/integration/utils/rates.js @@ -96,21 +96,21 @@ async function _setMissingRates({ ctx }) { const MockAggregatorFactory = await createMockAggregatorFactory(owner); // got over all rates and add aggregators - const { timestamp } = await ctx.provider.getBlock(); - for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { - for (const currencyKey of currencyKeys) { - const rate = await ExchangeRates.rateForCurrency(currencyKey); - if (rate.toString() === '0') { - // deploy an aggregator - let aggregator = await MockAggregatorFactory.deploy(); - aggregator = aggregator.connect(owner); - // set decimals - await (await aggregator.setDecimals(18)).wait(); + for (const currencyKey of currencyKeys) { + const rate = await ExchangeRates.rateForCurrency(currencyKey); + if (rate.toString() === '0') { + // deploy an aggregator + let aggregator = await MockAggregatorFactory.deploy(); + aggregator = aggregator.connect(owner); + // set decimals + await (await aggregator.setDecimals(18)).wait(); + for (let i = 0; i < EXCHANGE_DYNAMIC_FEE_ROUNDS; i++) { + const { timestamp } = await ctx.provider.getBlock(); // push the new price await (await aggregator.setLatestAnswer(ethers.utils.parseEther('1'), timestamp)).wait(); - // set the aggregator in ExchangeRates - await (await ExchangeRates.addAggregator(currencyKey, aggregator.address)).wait(); } + // set the aggregator in ExchangeRates + await (await ExchangeRates.addAggregator(currencyKey, aggregator.address)).wait(); } } } From 732e2cb7da0d1e932ea9fcf7eb221bf2fe8f7ace Mon Sep 17 00:00:00 2001 From: Lecky Date: Thu, 6 Jan 2022 14:11:28 +1100 Subject: [PATCH 10/11] Fix ExchangeRates.js - Using roundId 1 for sUSD to be consistent - Fix interface wrong compiler version warning --- contracts/interfaces/IExchanger.sol | 2 +- contracts/interfaces/IFlexibleStorage.sol | 2 +- test/contracts/ExchangeRates.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/interfaces/IExchanger.sol b/contracts/interfaces/IExchanger.sol index 2cd5323847..ce80bdfcc7 100644 --- a/contracts/interfaces/IExchanger.sol +++ b/contracts/interfaces/IExchanger.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.4.24; +pragma solidity ^0.5.16; import "./IVirtualSynth.sol"; diff --git a/contracts/interfaces/IFlexibleStorage.sol b/contracts/interfaces/IFlexibleStorage.sol index 4419f638be..e72cfbd801 100644 --- a/contracts/interfaces/IFlexibleStorage.sol +++ b/contracts/interfaces/IFlexibleStorage.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.4.24; +pragma solidity ^0.5.16; // https://docs.synthetix.io/contracts/source/interfaces/iflexiblestorage interface IFlexibleStorage { diff --git a/test/contracts/ExchangeRates.js b/test/contracts/ExchangeRates.js index 1d65f54832..57433e7050 100644 --- a/test/contracts/ExchangeRates.js +++ b/test/contracts/ExchangeRates.js @@ -948,8 +948,8 @@ contract('Exchange Rates', async accounts => { assert.equal(await instance.getCurrentRoundId(sBNB), 0); }); - it('getCurrentRoundId() is 0 for sUSD', async () => { - assert.equal(await instance.getCurrentRoundId(sUSD), 0); + it('getCurrentRoundId() is 1 for sUSD', async () => { + assert.equal(await instance.getCurrentRoundId(sUSD), 1); }); it('ratesAndUpdatedTimeForCurrencyLastNRounds() shows first entry for sUSD', async () => { From ab1b89cb0891466d8f99dab7ddf1091a1b2eed7a Mon Sep 17 00:00:00 2001 From: Lecky Date: Thu, 6 Jan 2022 16:55:54 +1100 Subject: [PATCH 11/11] Try to fix CI unit test - adding --max-old-space-size --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aa01c63629..5a69f1baeb 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "npm run describe && npm run pack", "fork": "node --max-old-space-size=4096 ./node_modules/.bin/hardhat node", "fork:mainnet": "node --max-old-space-size=4096 ./node_modules/.bin/hardhat node --target-network mainnet", - "test": "hardhat test", + "test": "node --max-old-space-size=4096 ./node_modules/.bin/hardhat test", "describe": "hardhat describe", "test:deployments": "mocha test/deployments -- --timeout 60000", "test:etherscan": "node test/etherscan",