diff --git a/contracts/erc20-bridge-sampler/CHANGELOG.json b/contracts/erc20-bridge-sampler/CHANGELOG.json index 4e044f6e95..619e31bd8b 100644 --- a/contracts/erc20-bridge-sampler/CHANGELOG.json +++ b/contracts/erc20-bridge-sampler/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "Catch reverts to `DevUtils` calls", "pr": 2476 + }, + { + "note": "Remove wrapper functions and introduce `batchCall()`", + "pr": 2477 } ], "timestamp": 1581204851 diff --git a/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol b/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol index 168976a058..357ac9d8e9 100644 --- a/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol +++ b/contracts/erc20-bridge-sampler/contracts/src/ERC20BridgeSampler.sol @@ -21,7 +21,6 @@ pragma experimental ABIEncoderV2; import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol"; import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol"; -import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; @@ -36,154 +35,36 @@ contract ERC20BridgeSampler is IERC20BridgeSampler, DeploymentConstants { - bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)")); - uint256 constant internal KYBER_SAMPLE_CALL_GAS = 1500e3; - uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3; - uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 1000e3; - uint256 constant internal DEV_UTILS_CALL_GAS = 500e3; - address constant private UNISWAP_SOURCE = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95; - address constant private ETH2DAI_SOURCE = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e; - address constant private KYBER_SOURCE = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755; + /// @dev Gas limit for DevUtils calls. + uint256 constant internal DEV_UTILS_CALL_GAS = 500e3; // 500k + /// @dev Gas limit for Kyber calls. + uint256 constant internal KYBER_CALL_GAS = 1500e3; // 1.5m + /// @dev Gas limit for Uniswap calls. + uint256 constant internal UNISWAP_CALL_GAS = 150e3; // 150k + /// @dev Base gas limit for Eth2Dai calls. + uint256 constant internal ETH2DAI_CALL_GAS = 1000e3; // 1m - /// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once. - /// @param orders Batches of Native orders to query. - /// @param orderSignatures Batches of Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param takerTokenAmounts Batches of Taker token sell amount for each sample. - /// @return ordersAndSamples How much taker asset can be filled - /// by each order in `orders`. Maker amounts bought for each source at - /// each taker token amount. First indexed by source index, then sample - /// index. - function queryBatchOrdersAndSampleSells( - LibOrder.Order[][] memory orders, - bytes[][] memory orderSignatures, - address[] memory sources, - uint256[][] memory takerTokenAmounts - ) - public + /// @dev Call multiple public functions on this contract in a single transaction. + /// @param callDatas ABI-encoded call data for each function call. + /// @return callResults ABI-encoded results data for each call. + function batchCall(bytes[] calldata callDatas) + external view - returns ( - OrdersAndSample[] memory ordersAndSamples - ) + returns (bytes[] memory callResults) { - ordersAndSamples = new OrdersAndSample[](orders.length); - for (uint256 i = 0; i != orders.length; i++) { - ( - uint256[] memory orderFillableAssetAmounts, - uint256[][] memory tokenAmountsBySource - ) = queryOrdersAndSampleSells(orders[i], orderSignatures[i], sources, takerTokenAmounts[i]); - ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts; - ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource; + callResults = new bytes[](callDatas.length); + for (uint256 i = 0; i != callDatas.length; ++i) { + (bool didSucceed, bytes memory resultData) = address(this).staticcall(callDatas[i]); + if (!didSucceed) { + assembly { revert(add(resultData, 0x20), mload(resultData)) } + } + callResults[i] = resultData; } } - /// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once. - /// @param orders Batches of Native orders to query. - /// @param orderSignatures Batches of Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param makerTokenAmounts Batches of Maker token sell amount for each sample. - /// @return ordersAndSamples How much taker asset can be filled - /// by each order in `orders`. Taker amounts sold for each source at - /// each maker token amount. First indexed by source index, then sample - /// index. - function queryBatchOrdersAndSampleBuys( - LibOrder.Order[][] memory orders, - bytes[][] memory orderSignatures, - address[] memory sources, - uint256[][] memory makerTokenAmounts - ) - public - view - returns ( - OrdersAndSample[] memory ordersAndSamples - ) - { - ordersAndSamples = new OrdersAndSample[](orders.length); - for (uint256 i = 0; i != orders.length; i++) { - ( - uint256[] memory orderFillableAssetAmounts, - uint256[][] memory tokenAmountsBySource - ) = queryOrdersAndSampleBuys(orders[i], orderSignatures[i], sources, makerTokenAmounts[i]); - ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts; - ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource; - } - } - - /// @dev Query native orders and sample sell quotes on multiple DEXes at once. - /// @param orders Native orders to query. - /// @param orderSignatures Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param takerTokenAmounts Taker token sell amount for each sample. - /// @return orderFillableTakerAssetAmounts How much taker asset can be filled - /// by each order in `orders`. - /// @return makerTokenAmountsBySource Maker amounts bought for each source at - /// each taker token amount. First indexed by source index, then sample - /// index. - function queryOrdersAndSampleSells( - LibOrder.Order[] memory orders, - bytes[] memory orderSignatures, - address[] memory sources, - uint256[] memory takerTokenAmounts - ) - public - view - returns ( - uint256[] memory orderFillableTakerAssetAmounts, - uint256[][] memory makerTokenAmountsBySource - ) - { - require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS"); - orderFillableTakerAssetAmounts = getOrderFillableTakerAssetAmounts( - orders, - orderSignatures - ); - makerTokenAmountsBySource = sampleSells( - sources, - _assetDataToTokenAddress(orders[0].takerAssetData), - _assetDataToTokenAddress(orders[0].makerAssetData), - takerTokenAmounts - ); - } - - /// @dev Query native orders and sample buy quotes on multiple DEXes at once. - /// @param orders Native orders to query. - /// @param orderSignatures Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param makerTokenAmounts Maker token buy amount for each sample. - /// @return orderFillableMakerAssetAmounts How much maker asset can be filled - /// by each order in `orders`. - /// @return takerTokenAmountsBySource Taker amounts sold for each source at - /// each maker token amount. First indexed by source index, then sample - /// index. - function queryOrdersAndSampleBuys( - LibOrder.Order[] memory orders, - bytes[] memory orderSignatures, - address[] memory sources, - uint256[] memory makerTokenAmounts - ) - public - view - returns ( - uint256[] memory orderFillableMakerAssetAmounts, - uint256[][] memory makerTokenAmountsBySource - ) - { - require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS"); - orderFillableMakerAssetAmounts = getOrderFillableMakerAssetAmounts( - orders, - orderSignatures - ); - makerTokenAmountsBySource = sampleBuys( - sources, - _assetDataToTokenAddress(orders[0].takerAssetData), - _assetDataToTokenAddress(orders[0].makerAssetData), - makerTokenAmounts - ); - } - /// @dev Queries the fillable taker asset amounts of native orders. /// Effectively ignores orders that have empty signatures or - /// maker/taker asset amounts (returning 0). + /// maker/taker asset amounts (returning 0). /// @param orders Native orders to query. /// @param orderSignatures Signatures for each respective order in `orders`. /// @return orderFillableTakerAssetAmounts How much taker asset can be filled @@ -270,66 +151,6 @@ contract ERC20BridgeSampler is } } - /// @dev Sample sell quotes on multiple DEXes at once. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param takerToken Address of the taker token (what to sell). - /// @param makerToken Address of the maker token (what to buy). - /// @param takerTokenAmounts Taker token sell amount for each sample. - /// @return makerTokenAmountsBySource Maker amounts bought for each source at - /// each taker token amount. First indexed by source index, then sample - /// index. - function sampleSells( - address[] memory sources, - address takerToken, - address makerToken, - uint256[] memory takerTokenAmounts - ) - public - view - returns (uint256[][] memory makerTokenAmountsBySource) - { - uint256 numSources = sources.length; - makerTokenAmountsBySource = new uint256[][](numSources); - for (uint256 i = 0; i < numSources; i++) { - makerTokenAmountsBySource[i] = _sampleSellSource( - sources[i], - takerToken, - makerToken, - takerTokenAmounts - ); - } - } - - /// @dev Query native orders and sample buy quotes on multiple DEXes at once. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param takerToken Address of the taker token (what to sell). - /// @param makerToken Address of the maker token (what to buy). - /// @param makerTokenAmounts Maker token buy amount for each sample. - /// @return takerTokenAmountsBySource Taker amounts sold for each source at - /// each maker token amount. First indexed by source index, then sample - /// index. - function sampleBuys( - address[] memory sources, - address takerToken, - address makerToken, - uint256[] memory makerTokenAmounts - ) - public - view - returns (uint256[][] memory takerTokenAmountsBySource) - { - uint256 numSources = sources.length; - takerTokenAmountsBySource = new uint256[][](numSources); - for (uint256 i = 0; i < numSources; i++) { - takerTokenAmountsBySource[i] = _sampleBuySource( - sources[i], - takerToken, - makerToken, - makerTokenAmounts - ); - } - } - /// @dev Sample sell quotes from Kyber. /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). @@ -354,7 +175,7 @@ contract ERC20BridgeSampler is makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { (bool didSucceed, bytes memory resultData) = - _getKyberNetworkProxyAddress().staticcall.gas(KYBER_SAMPLE_CALL_GAS)( + _getKyberNetworkProxyAddress().staticcall.gas(KYBER_CALL_GAS)( abi.encodeWithSelector( IKyberNetwork(0).getExpectedRate.selector, _takerToken, @@ -396,7 +217,7 @@ contract ERC20BridgeSampler is makerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { (bool didSucceed, bytes memory resultData) = - _getEth2DaiAddress().staticcall.gas(ETH2DAI_SAMPLE_CALL_GAS)( + _getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)( abi.encodeWithSelector( IEth2Dai(0).getBuyAmount.selector, makerToken, @@ -433,7 +254,7 @@ contract ERC20BridgeSampler is takerTokenAmounts = new uint256[](numSamples); for (uint256 i = 0; i < numSamples; i++) { (bool didSucceed, bytes memory resultData) = - _getEth2DaiAddress().staticcall.gas(ETH2DAI_SAMPLE_CALL_GAS)( + _getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)( abi.encodeWithSelector( IEth2Dai(0).getPayAmount.selector, takerToken, @@ -599,7 +420,7 @@ contract ERC20BridgeSampler is } bytes memory resultData; (didSucceed, resultData) = - uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)( + uniswapExchangeAddress.staticcall.gas(UNISWAP_CALL_GAS)( abi.encodeWithSelector( functionSelector, inputAmount @@ -609,59 +430,6 @@ contract ERC20BridgeSampler is } } - /// @dev Samples a supported sell source, defined by its address. - /// @param takerToken Address of the taker token (what to sell). - /// @param makerToken Address of the maker token (what to buy). - /// @param takerTokenAmounts Taker token sell amount for each sample. - /// @return makerTokenAmounts Maker amounts bought at each taker token - /// amount. - function _sampleSellSource( - address source, - address takerToken, - address makerToken, - uint256[] memory takerTokenAmounts - ) - private - view - returns (uint256[] memory makerTokenAmounts) - { - if (source == ETH2DAI_SOURCE) { - return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts); - } - if (source == UNISWAP_SOURCE) { - return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts); - } - if (source == KYBER_SOURCE) { - return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts); - } - revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE"); - } - - /// @dev Samples a supported buy source, defined by its address. - /// @param takerToken Address of the taker token (what to sell). - /// @param makerToken Address of the maker token (what to buy). - /// @param makerTokenAmounts Maker token sell amount for each sample. - /// @return takerTokenAmounts Taker amounts sold at each maker token - /// amount. - function _sampleBuySource( - address source, - address takerToken, - address makerToken, - uint256[] memory makerTokenAmounts - ) - private - view - returns (uint256[] memory takerTokenAmounts) - { - if (source == ETH2DAI_SOURCE) { - return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts); - } - if (source == UNISWAP_SOURCE) { - return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts); - } - revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE"); - } - /// @dev Retrive an existing Uniswap exchange contract. /// Throws if the exchange does not exist. /// @param tokenAddress Address of the token contract. @@ -677,23 +445,9 @@ contract ERC20BridgeSampler is ); } - /// @dev Extract the token address from ERC20 proxy asset data. - /// @param assetData ERC20 asset data. - /// @return tokenAddress The decoded token address. - function _assetDataToTokenAddress(bytes memory assetData) - private - pure - returns (address tokenAddress) - { - require(assetData.length == 36, "ERC20BridgeSampler/INVALID_ASSET_DATA"); - bytes4 selector; - assembly { - selector := and(mload(add(assetData, 0x20)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000) - tokenAddress := mload(add(assetData, 0x24)) - } - require(selector == ERC20_PROXY_ID, "ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY"); - } - + /// @dev Assert that the tokens in a trade pair are valid. + /// @param makerToken Address of the maker token. + /// @param takerToken Address of the taker token. function _assertValidPair(address makerToken, address takerToken) private pure diff --git a/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol b/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol index 42661de16d..a5b69047d0 100644 --- a/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol +++ b/contracts/erc20-bridge-sampler/contracts/src/IERC20BridgeSampler.sol @@ -23,98 +23,14 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; interface IERC20BridgeSampler { - struct OrdersAndSample { - uint256[] orderFillableAssetAmounts; - uint256[][] tokenAmountsBySource; - } - /// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once. - /// @param orders Batches of Native orders to query. - /// @param orderSignatures Batches of Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param takerTokenAmounts Batches of Taker token sell amount for each sample. - /// @return ordersAndSamples How much taker asset can be filled - /// by each order in `orders`. Maker amounts bought for each source at - /// each taker token amount. First indexed by source index, then sample - /// index. - function queryBatchOrdersAndSampleSells( - LibOrder.Order[][] calldata orders, - bytes[][] calldata orderSignatures, - address[] calldata sources, - uint256[][] calldata takerTokenAmounts - ) + /// @dev Call multiple public functions on this contract in a single transaction. + /// @param callDatas ABI-encoded call data for each function call. + /// @return callResults ABI-encoded results data for each call. + function batchCall(bytes[] calldata callDatas) external view - returns ( - OrdersAndSample[] memory ordersAndSamples - ); - - /// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once. - /// @param orders Batches of Native orders to query. - /// @param orderSignatures Batches of Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param makerTokenAmounts Batches of Maker token sell amount for each sample. - /// @return ordersAndSamples How much taker asset can be filled - /// by each order in `orders`. Taker amounts sold for each source at - /// each maker token amount. First indexed by source index, then sample - /// index - function queryBatchOrdersAndSampleBuys( - LibOrder.Order[][] calldata orders, - bytes[][] calldata orderSignatures, - address[] calldata sources, - uint256[][] calldata makerTokenAmounts - ) - external - view - returns ( - OrdersAndSample[] memory ordersAndSamples - ); - - /// @dev Query native orders and sample sell quotes on multiple DEXes at once. - /// @param orders Native orders to query. - /// @param orderSignatures Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param takerTokenAmounts Taker token sell amount for each sample. - /// @return orderFillableTakerAssetAmounts How much taker asset can be filled - /// by each order in `orders`. - /// @return makerTokenAmountsBySource Maker amounts bought for each source at - /// each taker token amount. First indexed by source index, then sample - /// index. - function queryOrdersAndSampleSells( - LibOrder.Order[] calldata orders, - bytes[] calldata orderSignatures, - address[] calldata sources, - uint256[] calldata takerTokenAmounts - ) - external - view - returns ( - uint256[] memory orderFillableTakerAssetAmounts, - uint256[][] memory makerTokenAmountsBySource - ); - - /// @dev Query native orders and sample buy quotes on multiple DEXes at once. - /// @param orders Native orders to query. - /// @param orderSignatures Signatures for each respective order in `orders`. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. - /// @param makerTokenAmounts Maker token buy amount for each sample. - /// @return orderFillableMakerAssetAmounts How much maker asset can be filled - /// by each order in `orders`. - /// @return takerTokenAmountsBySource Taker amounts sold for each source at - /// each maker token amount. First indexed by source index, then sample - /// index. - function queryOrdersAndSampleBuys( - LibOrder.Order[] calldata orders, - bytes[] calldata orderSignatures, - address[] calldata sources, - uint256[] calldata makerTokenAmounts - ) - external - view - returns ( - uint256[] memory orderFillableMakerAssetAmounts, - uint256[][] memory makerTokenAmountsBySource - ); + returns (bytes[] memory callResults); /// @dev Queries the fillable taker asset amounts of native orders. /// @param orders Native orders to query. @@ -142,39 +58,78 @@ interface IERC20BridgeSampler { view returns (uint256[] memory orderFillableMakerAssetAmounts); - /// @dev Sample sell quotes on multiple DEXes at once. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. + /// @dev Sample sell quotes from Kyber. /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). /// @param takerTokenAmounts Taker token sell amount for each sample. - /// @return makerTokenAmountsBySource Maker amounts bought for each source at - /// each taker token amount. First indexed by source index, then sample - /// index. - function sampleSells( - address[] calldata sources, + /// @return makerTokenAmounts Maker amounts bought at each taker token + /// amount. + function sampleSellsFromKyberNetwork( address takerToken, address makerToken, uint256[] calldata takerTokenAmounts ) external view - returns (uint256[][] memory makerTokenAmountsBySource); + returns (uint256[] memory makerTokenAmounts); - /// @dev Query native orders and sample buy quotes on multiple DEXes at once. - /// @param sources Address of each DEX. Passing in an unsupported DEX will throw. + /// @dev Sample sell quotes from Eth2Dai/Oasis. /// @param takerToken Address of the taker token (what to sell). /// @param makerToken Address of the maker token (what to buy). - /// @param makerTokenAmounts Maker token buy amount for each sample. - /// @return takerTokenAmountsBySource Taker amounts sold for each source at - /// each maker token amount. First indexed by source index, then sample - /// index. - function sampleBuys( - address[] calldata sources, + /// @param takerTokenAmounts Taker token sell amount for each sample. + /// @return makerTokenAmounts Maker amounts bought at each taker token + /// amount. + function sampleSellsFromEth2Dai( + address takerToken, + address makerToken, + uint256[] calldata takerTokenAmounts + ) + external + view + returns (uint256[] memory makerTokenAmounts); + + /// @dev Sample sell quotes from Uniswap. + /// @param takerToken Address of the taker token (what to sell). + /// @param makerToken Address of the maker token (what to buy). + /// @param takerTokenAmounts Taker token sell amount for each sample. + /// @return makerTokenAmounts Maker amounts bought at each taker token + /// amount. + function sampleSellsFromUniswap( + address takerToken, + address makerToken, + uint256[] calldata takerTokenAmounts + ) + external + view + returns (uint256[] memory makerTokenAmounts); + + /// @dev Sample buy quotes from Uniswap. + /// @param takerToken Address of the taker token (what to sell). + /// @param makerToken Address of the maker token (what to buy). + /// @param makerTokenAmounts Maker token sell amount for each sample. + /// @return takerTokenAmounts Taker amounts sold at each maker token + /// amount. + function sampleBuysFromUniswap( address takerToken, address makerToken, uint256[] calldata makerTokenAmounts ) external view - returns (uint256[][] memory takerTokenAmountsBySource); + returns (uint256[] memory takerTokenAmounts); + + /// @dev Sample buy quotes from Eth2Dai/Oasis. + /// @param takerToken Address of the taker token (what to sell). + /// @param makerToken Address of the maker token (what to buy). + /// @param takerTokenAmounts Maker token sell amount for each sample. + /// @return takerTokenAmounts Taker amounts sold at each maker token + /// amount. + function sampleBuysFromEth2Dai( + address takerToken, + address makerToken, + uint256[] calldata makerTokenAmounts + ) + external + view + returns (uint256[] memory takerTokenAmounts); } diff --git a/contracts/erc20-bridge-sampler/contracts/test/TestERC20BridgeSampler.sol b/contracts/erc20-bridge-sampler/contracts/test/TestERC20BridgeSampler.sol index 09ad84d197..06242d91b2 100644 --- a/contracts/erc20-bridge-sampler/contracts/test/TestERC20BridgeSampler.sol +++ b/contracts/erc20-bridge-sampler/contracts/test/TestERC20BridgeSampler.sol @@ -327,7 +327,6 @@ contract TestERC20BridgeSampler is bytes memory ) public - view returns ( LibOrder.OrderInfo memory orderInfo, uint256 fillableTakerAssetAmount, diff --git a/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts b/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts index cf5d82a330..d51d7285d9 100644 --- a/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts +++ b/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts @@ -25,19 +25,6 @@ blockchainTests('erc20-bridge-sampler', env => { const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7'; const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab'; const ERC20_PROXY_ID = '0xf47261b0'; - const INVALID_ASSET_PROXY_ASSET_DATA = hexUtils.concat('0xf47261b1', hexUtils.leftPad(randomAddress())); - const INVALID_ASSET_DATA = hexUtils.random(37); - const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap']; - const BUY_SOURCES = ['Eth2Dai', 'Uniswap']; - const SOURCE_IDS: { [source: string]: string } = { - Uniswap: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95', - Eth2Dai: '0x39755357759ce0d7f32dc8dc45414cca409ae24e', - Kyber: '0x818e6fecd516ecc3849daf6845e3ec868087b755', - }; - const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS'; - const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY'; - const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA'; - const UNSUPPORTED_SOURCE_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_SOURCE'; const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR'; const MAKER_TOKEN = randomAddress(); const TAKER_TOKEN = randomAddress(); @@ -190,7 +177,7 @@ blockchainTests('erc20-bridge-sampler', env => { } function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber { - const hash = getPackedHash(hexUtils.toHex(order.salt, 32)); + const hash = getPackedHash(hexUtils.leftPad(order.salt)); const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3; const isValidSignature = !!new BigNumber(hash).mod(2).toNumber(); if (orderStatus !== 3 || !isValidSignature) { @@ -324,329 +311,6 @@ blockchainTests('erc20-bridge-sampler', env => { }); }); - describe('queryOrdersAndSampleSells()', () => { - const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN); - const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random()); - - before(async () => { - await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync(); - }); - - it('returns expected fillable amounts for each order', async () => { - const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN); - const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount); - const [orderInfos] = await testContract - .queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts) - .callAsync(); - expect(orderInfos).to.deep.eq(expectedFillableAmounts); - }); - - it('can return quotes for all sources', async () => { - const sampleAmounts = getSampleAmounts(TAKER_TOKEN); - const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts); - const [, quotes] = await testContract - .queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts) - .callAsync(); - expect(quotes).to.deep.eq(expectedQuotes); - }); - - it('throws if no orders are passed in', async () => { - const tx = testContract - .queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(TAKER_TOKEN)) - .callAsync(); - return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR); - }); - - it('throws with an unsupported source', async () => { - const tx = testContract - .queryOrdersAndSampleSells( - ORDERS, - SIGNATURES, - [...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()], - getSampleAmounts(TAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR); - }); - - it('throws with non-ERC20 maker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleSells( - ORDERS.map(o => ({ - ...o, - makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, - })), - SIGNATURES, - SELL_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(TAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR); - }); - - it('throws with non-ERC20 taker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleSells( - ORDERS.map(o => ({ - ...o, - takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, - })), - SIGNATURES, - SELL_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(TAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR); - }); - - it('throws with invalid maker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleSells( - ORDERS.map(o => ({ - ...o, - makerAssetData: INVALID_ASSET_DATA, - })), - SIGNATURES, - SELL_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(TAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR); - }); - - it('throws with invalid taker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleSells( - ORDERS.map(o => ({ - ...o, - takerAssetData: INVALID_ASSET_DATA, - })), - SIGNATURES, - SELL_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(TAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR); - }); - }); - - describe('queryOrdersAndSampleBuys()', () => { - const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN); - const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random()); - - before(async () => { - await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync(); - }); - - it('returns expected fillable amounts for each order', async () => { - const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN); - const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount); - const [orderInfos] = await testContract - .queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts) - .callAsync(); - expect(orderInfos).to.deep.eq(expectedFillableAmounts); - }); - - it('can return quotes for all sources', async () => { - const sampleAmounts = getSampleAmounts(MAKER_TOKEN); - const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts); - const [, quotes] = await testContract - .queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts) - .callAsync(); - expect(quotes).to.deep.eq(expectedQuotes); - }); - - it('throws if no orders are passed in', async () => { - const tx = testContract - .queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(MAKER_TOKEN)) - .callAsync(); - return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR); - }); - - it('throws with an unsupported source', async () => { - const tx = testContract - .queryOrdersAndSampleBuys( - ORDERS, - SIGNATURES, - [...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()], - getSampleAmounts(MAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR); - }); - - it('throws if kyber is passed in as a source', async () => { - const sources = [...BUY_SOURCES, 'Kyber']; - const tx = testContract - .queryOrdersAndSampleBuys( - ORDERS, - SIGNATURES, - sources.map(n => SOURCE_IDS[n]), - getSampleAmounts(MAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR); - }); - - it('throws with non-ERC20 maker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleBuys( - ORDERS.map(o => ({ - ...o, - makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, - })), - SIGNATURES, - BUY_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(MAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR); - }); - - it('throws with non-ERC20 taker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleBuys( - ORDERS.map(o => ({ - ...o, - takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA, - })), - SIGNATURES, - BUY_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(MAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR); - }); - - it('throws with invalid maker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleBuys( - ORDERS.map(o => ({ - ...o, - makerAssetData: INVALID_ASSET_DATA, - })), - SIGNATURES, - BUY_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(MAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR); - }); - - it('throws with invalid taker asset data', async () => { - const tx = testContract - .queryOrdersAndSampleBuys( - ORDERS.map(o => ({ - ...o, - takerAssetData: INVALID_ASSET_DATA, - })), - SIGNATURES, - BUY_SOURCES.map(n => SOURCE_IDS[n]), - getSampleAmounts(MAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR); - }); - }); - - describe('sampleSells()', () => { - before(async () => { - await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync(); - }); - - it('returns empty quotes with no sample amounts', async () => { - const emptyQuotes = _.times(SELL_SOURCES.length, () => []); - const quotes = await testContract - .sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, []) - .callAsync(); - expect(quotes).to.deep.eq(emptyQuotes); - }); - - it('can return quotes for all sources', async () => { - const sampleAmounts = getSampleAmounts(TAKER_TOKEN); - const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts); - const quotes = await testContract - .sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) - .callAsync(); - expect(quotes).to.deep.eq(expectedQuotes); - }); - - it('can return quotes for some sources', async () => { - const sampleAmounts = getSampleAmounts(TAKER_TOKEN); - const sources = _.sampleSize(SELL_SOURCES, 1); - const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts); - const quotes = await testContract - .sampleSells(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) - .callAsync(); - expect(quotes).to.deep.eq(expectedQuotes); - }); - - it('throws with an unsupported source', async () => { - const tx = testContract - .sampleSells( - [...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()], - TAKER_TOKEN, - MAKER_TOKEN, - getSampleAmounts(TAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR); - }); - }); - - describe('sampleBuys()', () => { - before(async () => { - await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync(); - }); - - it('returns empty quotes with no sample amounts', async () => { - const emptyQuotes = _.times(BUY_SOURCES.length, () => []); - const quotes = await testContract - .sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, []) - .callAsync(); - expect(quotes).to.deep.eq(emptyQuotes); - }); - - it('can return quotes for all sources', async () => { - const sampleAmounts = getSampleAmounts(MAKER_TOKEN); - const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts); - const quotes = await testContract - .sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) - .callAsync(); - expect(quotes).to.deep.eq(expectedQuotes); - }); - - it('can return quotes for some sources', async () => { - const sampleAmounts = getSampleAmounts(MAKER_TOKEN); - const sources = _.sampleSize(BUY_SOURCES, 1); - const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts); - const quotes = await testContract - .sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts) - .callAsync(); - expect(quotes).to.deep.eq(expectedQuotes); - }); - - it('throws with an unsupported source', async () => { - const tx = testContract - .sampleBuys( - [...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()], - TAKER_TOKEN, - MAKER_TOKEN, - getSampleAmounts(MAKER_TOKEN), - ) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR); - }); - - it('throws if kyber is passed in as a source', async () => { - const sources = [...BUY_SOURCES, 'Kyber']; - const tx = testContract - .sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN)) - .callAsync(); - return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR); - }); - }); - blockchainTests.resets('sampleSellsFromKyberNetwork()', () => { before(async () => { await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync(); @@ -1051,4 +715,65 @@ blockchainTests('erc20-bridge-sampler', env => { expect(quotes).to.deep.eq(expectedQuotes); }); }); + + describe('batchCall()', () => { + it('can call one function', async () => { + const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN); + const signatures: string[] = _.times(orders.length, i => hexUtils.random()); + const expected = orders.map(getDeterministicFillableTakerAssetAmount); + const calls = [ + testContract.getOrderFillableTakerAssetAmounts(orders, signatures).getABIEncodedTransactionData(), + ]; + const r = await testContract.batchCall(calls).callAsync(); + expect(r).to.be.length(1); + const actual = testContract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', r[0]); + expect(actual).to.deep.eq(expected); + }); + + it('can call two functions', async () => { + const numOrders = _.random(1, 10); + const orders = _.times(2, () => createOrders(MAKER_TOKEN, TAKER_TOKEN, numOrders)); + const signatures: string[] = _.times(numOrders, i => hexUtils.random()); + const expecteds = [ + orders[0].map(getDeterministicFillableTakerAssetAmount), + orders[1].map(getDeterministicFillableMakerAssetAmount), + ]; + const calls = [ + testContract.getOrderFillableTakerAssetAmounts(orders[0], signatures).getABIEncodedTransactionData(), + testContract.getOrderFillableMakerAssetAmounts(orders[1], signatures).getABIEncodedTransactionData(), + ]; + const r = await testContract.batchCall(calls).callAsync(); + expect(r).to.be.length(2); + expect(testContract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', r[0])).to.deep.eq( + expecteds[0], + ); + expect(testContract.getABIDecodedReturnData('getOrderFillableMakerAssetAmounts', r[1])).to.deep.eq( + expecteds[1], + ); + }); + + it('can make recursive calls', async () => { + const numOrders = _.random(1, 10); + const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, numOrders); + const signatures: string[] = _.times(numOrders, i => hexUtils.random()); + const expected = orders.map(getDeterministicFillableTakerAssetAmount); + let r = await testContract + .batchCall([ + testContract + .batchCall([ + testContract + .getOrderFillableTakerAssetAmounts(orders, signatures) + .getABIEncodedTransactionData(), + ]) + .getABIEncodedTransactionData(), + ]) + .callAsync(); + expect(r).to.be.length(1); + r = testContract.getABIDecodedReturnData('batchCall', r[0]); + expect(r).to.be.length(1); + expect(testContract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', r[0])).to.deep.eq( + expected, + ); + }); + }); }); diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index 267db994f7..6e578cbcce 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "4.2.0", + "changes": [ + { + "note": "Use `batchCall()` version of the `ERC20BridgeSampler` contract", + "pr": 2477 + } + ] + }, { "timestamp": 1581204851, "version": "4.1.2", diff --git a/packages/asset-swapper/src/swap_quoter.ts b/packages/asset-swapper/src/swap_quoter.ts index 602e0213e6..063c045ac1 100644 --- a/packages/asset-swapper/src/swap_quoter.ts +++ b/packages/asset-swapper/src/swap_quoter.ts @@ -21,7 +21,7 @@ import { } from './types'; import { assert } from './utils/assert'; import { calculateLiquidity } from './utils/calculate_liquidity'; -import { MarketOperationUtils } from './utils/market_operation_utils'; +import { DexOrderSampler, MarketOperationUtils } from './utils/market_operation_utils'; import { dummyOrderUtils } from './utils/market_operation_utils/dummy_order_utils'; import { orderPrunerUtils } from './utils/order_prune_utils'; import { OrderStateUtils } from './utils/order_state_utils'; @@ -162,12 +162,12 @@ export class SwapQuoter { this._devUtilsContract = new DevUtilsContract(this._contractAddresses.devUtils, provider); this._protocolFeeUtils = new ProtocolFeeUtils(constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS); this._orderStateUtils = new OrderStateUtils(this._devUtilsContract); - const samplerContract = new IERC20BridgeSamplerContract( - this._contractAddresses.erc20BridgeSampler, - this.provider, - { gas: samplerGasLimit }, + const sampler = new DexOrderSampler( + new IERC20BridgeSamplerContract(this._contractAddresses.erc20BridgeSampler, this.provider, { + gas: samplerGasLimit, + }), ); - this._marketOperationUtils = new MarketOperationUtils(samplerContract, this._contractAddresses, { + this._marketOperationUtils = new MarketOperationUtils(sampler, this._contractAddresses, { chainId, exchangeAddress: this._contractAddresses.exchange, }); diff --git a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts index 620f7e90b8..485e2c89d7 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -4,15 +4,6 @@ import { ERC20BridgeSource, GetMarketOrdersOpts } from './types'; const INFINITE_TIMESTAMP_SEC = new BigNumber(2524604400); -/** - * Convert a source to a canonical address used by the sampler contract. - */ -const SOURCE_TO_ADDRESS: { [key: string]: string } = { - [ERC20BridgeSource.Eth2Dai]: '0x39755357759ce0d7f32dc8dc45414cca409ae24e', - [ERC20BridgeSource.Uniswap]: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95', - [ERC20BridgeSource.Kyber]: '0x818e6fecd516ecc3849daf6845e3ec868087b755', -}; - /** * Valid sources for market sell. */ @@ -36,7 +27,6 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = { export const constants = { INFINITE_TIMESTAMP_SEC, - SOURCE_TO_ADDRESS, SELL_SOURCES, BUY_SOURCES, DEFAULT_GET_MARKET_ORDERS_OPTS, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/index.ts b/packages/asset-swapper/src/utils/market_operation_utils/index.ts index aed438f35e..748e551a42 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -1,5 +1,4 @@ import { ContractAddresses } from '@0x/contract-addresses'; -import { IERC20BridgeSamplerContract } from '@0x/contract-wrappers'; import { assetDataUtils, ERC20AssetData, orderCalculationUtils } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -11,7 +10,7 @@ import { fillableAmountsUtils } from '../fillable_amounts_utils'; import { constants as marketOperationUtilConstants } from './constants'; import { CreateOrderUtils } from './create_order'; import { comparePathOutputs, FillsOptimizer, getPathOutput } from './fill_optimizer'; -import { DexOrderSampler } from './sampler'; +import { DexOrderSampler, getSampleAmounts } from './sampler'; import { AggregationError, CollapsedFill, @@ -27,22 +26,20 @@ import { OrderDomain, } from './types'; +export { DexOrderSampler } from './sampler'; + const { ZERO_AMOUNT } = constants; const { BUY_SOURCES, DEFAULT_GET_MARKET_ORDERS_OPTS, ERC20_PROXY_ID, SELL_SOURCES } = marketOperationUtilConstants; export class MarketOperationUtils { - private readonly _dexSampler: DexOrderSampler; private readonly _createOrderUtils: CreateOrderUtils; - private readonly _orderDomain: OrderDomain; constructor( - samplerContract: IERC20BridgeSamplerContract, + private readonly _sampler: DexOrderSampler, contractAddresses: ContractAddresses, - orderDomain: OrderDomain, + private readonly _orderDomain: OrderDomain, ) { - this._dexSampler = new DexOrderSampler(samplerContract); this._createOrderUtils = new CreateOrderUtils(contractAddresses); - this._orderDomain = orderDomain; } /** @@ -65,10 +62,15 @@ export class MarketOperationUtils { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts, }; - const [fillableAmounts, dexQuotes] = await this._dexSampler.getFillableAmountsAndSampleMarketSellAsync( - nativeOrders, - DexOrderSampler.getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase), - difference(SELL_SOURCES, _opts.excludedSources), + const [makerToken, takerToken] = getOrderTokens(nativeOrders[0]); + const [fillableAmounts, dexQuotes] = await this._sampler.executeAsync( + DexOrderSampler.ops.getOrderFillableTakerAmounts(nativeOrders), + DexOrderSampler.ops.getSellQuotes( + difference(SELL_SOURCES, _opts.excludedSources), + makerToken, + takerToken, + getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase), + ), ); const nativeOrdersWithFillableAmounts = createSignedOrdersWithFillableAmounts( nativeOrders, @@ -104,11 +106,10 @@ export class MarketOperationUtils { if (!optimalPath) { throw new Error(AggregationError.NoOptimalPath); } - const [outputToken, inputToken] = getOrderTokens(nativeOrders[0]); return this._createOrderUtils.createSellOrdersFromPath( this._orderDomain, - inputToken, - outputToken, + takerToken, + makerToken, collapsePath(optimalPath, false), _opts.bridgeSlippage, ); @@ -134,11 +135,15 @@ export class MarketOperationUtils { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts, }; - - const [fillableAmounts, dexQuotes] = await this._dexSampler.getFillableAmountsAndSampleMarketBuyAsync( - nativeOrders, - DexOrderSampler.getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase), - difference(BUY_SOURCES, _opts.excludedSources), + const [makerToken, takerToken] = getOrderTokens(nativeOrders[0]); + const [fillableAmounts, dexQuotes] = await this._sampler.executeAsync( + DexOrderSampler.ops.getOrderFillableMakerAmounts(nativeOrders), + DexOrderSampler.ops.getBuyQuotes( + difference(BUY_SOURCES, _opts.excludedSources), + makerToken, + takerToken, + getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase), + ), ); const signedOrderWithFillableAmounts = this._createBuyOrdersPathFromSamplerResultIfExists( nativeOrders, @@ -174,17 +179,25 @@ export class MarketOperationUtils { ...opts, }; - const batchSampleResults = await this._dexSampler.getBatchFillableAmountsAndSampleMarketBuyAsync( - batchNativeOrders, - makerAmounts.map(makerAmount => DexOrderSampler.getSampleAmounts(makerAmount, _opts.numSamples)), - difference(BUY_SOURCES, _opts.excludedSources), - ); - return batchSampleResults.map(([fillableAmounts, dexQuotes], i) => + const sources = difference(BUY_SOURCES, _opts.excludedSources); + const ops = [ + ...batchNativeOrders.map(orders => DexOrderSampler.ops.getOrderFillableMakerAmounts(orders)), + ...batchNativeOrders.map((orders, i) => + DexOrderSampler.ops.getBuyQuotes(sources, getOrderTokens(orders[0])[0], getOrderTokens(orders[0])[1], [ + makerAmounts[i], + ]), + ), + ]; + const executeResults = await this._sampler.executeBatchAsync(ops); + const batchFillableAmounts = executeResults.slice(0, batchNativeOrders.length) as BigNumber[][]; + const batchDexQuotes = executeResults.slice(batchNativeOrders.length) as DexSample[][][]; + + return batchFillableAmounts.map((fillableAmounts, i) => this._createBuyOrdersPathFromSamplerResultIfExists( batchNativeOrders[i], makerAmounts[i], fillableAmounts, - dexQuotes, + batchDexQuotes[i], _opts, ), ); diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts index 078b5cd9cf..e7a687c55b 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts @@ -2,99 +2,330 @@ import { IERC20BridgeSamplerContract } from '@0x/contract-wrappers'; import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import { constants as marketOperationUtilConstants } from './constants'; import { DexSample, ERC20BridgeSource } from './types'; -const { SOURCE_TO_ADDRESS } = marketOperationUtilConstants; +/** + * A composable operation the be run in `DexOrderSampler.executeAsync()`. + */ +export interface BatchedOperation { + encodeCall(contract: IERC20BridgeSamplerContract): string; + handleCallResultsAsync(contract: IERC20BridgeSamplerContract, callResults: string): Promise; +} -export class DexOrderSampler { - private readonly _samplerContract: IERC20BridgeSamplerContract; - - /** - * Generate sample amounts up to `maxFillAmount`. - */ - public static getSampleAmounts(maxFillAmount: BigNumber, numSamples: number, expBase: number = 1): BigNumber[] { - const distribution = [...Array(numSamples)].map((v, i) => new BigNumber(expBase).pow(i)); - const stepSizes = distribution.map(d => d.div(BigNumber.sum(...distribution))); - const amounts = stepSizes.map((s, i) => { - return maxFillAmount - .times(BigNumber.sum(...[0, ...stepSizes.slice(0, i + 1)])) - .integerValue(BigNumber.ROUND_UP); +/** + * Composable operations that can be batched in a single transaction, + * for use with `DexOrderSampler.executeAsync()`. + */ +const samplerOperations = { + getOrderFillableTakerAmounts(orders: SignedOrder[]): BatchedOperation { + return { + encodeCall: contract => { + return contract + .getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature)) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', callResults); + }, + }; + }, + getOrderFillableMakerAmounts(orders: SignedOrder[]): BatchedOperation { + return { + encodeCall: contract => { + return contract + .getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature)) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('getOrderFillableMakerAssetAmounts', callResults); + }, + }; + }, + getKyberSellQuotes( + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromKyberNetwork(takerToken, makerToken, takerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleSellsFromKyberNetwork', callResults); + }, + }; + }, + getUniswapSellQuotes( + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromUniswap(takerToken, makerToken, takerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleSellsFromUniswap', callResults); + }, + }; + }, + getEth2DaiSellQuotes( + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromEth2Dai(takerToken, makerToken, takerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleSellsFromEth2Dai', callResults); + }, + }; + }, + getUniswapBuyQuotes( + makerToken: string, + takerToken: string, + makerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleBuysFromUniswap(takerToken, makerToken, makerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleBuysFromUniswap', callResults); + }, + }; + }, + getEth2DaiBuyQuotes( + makerToken: string, + takerToken: string, + makerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleBuysFromEth2Dai(takerToken, makerToken, makerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleBuysFromEth2Dai', callResults); + }, + }; + }, + getSellQuotes( + sources: ERC20BridgeSource[], + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + const subOps = sources.map(source => { + if (source === ERC20BridgeSource.Eth2Dai) { + return samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts); + } else if (source === ERC20BridgeSource.Uniswap) { + return samplerOperations.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts); + } else if (source === ERC20BridgeSource.Kyber) { + return samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts); + } else { + throw new Error(`Unsupported sell sample source: ${source}`); + } }); - return amounts; - } + return { + encodeCall: contract => { + const subCalls = subOps.map(op => op.encodeCall(contract)); + return contract.batchCall(subCalls).getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); + const samples = await Promise.all( + subOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])), + ); + return sources.map((source, i) => { + return samples[i].map((output, j) => ({ + source, + output, + input: takerFillAmounts[j], + })); + }); + }, + }; + }, + getBuyQuotes( + sources: ERC20BridgeSource[], + makerToken: string, + takerToken: string, + makerFillAmounts: BigNumber[], + ): BatchedOperation { + const subOps = sources.map(source => { + if (source === ERC20BridgeSource.Eth2Dai) { + return samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts); + } else if (source === ERC20BridgeSource.Uniswap) { + return samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts); + } else { + throw new Error(`Unsupported buy sample source: ${source}`); + } + }); + return { + encodeCall: contract => { + const subCalls = subOps.map(op => op.encodeCall(contract)); + return contract.batchCall(subCalls).getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); + const samples = await Promise.all( + subOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])), + ); + return sources.map((source, i) => { + return samples[i].map((output, j) => ({ + source, + output, + input: makerFillAmounts[j], + })); + }); + }, + }; + }, +}; + +/** + * Generate sample amounts up to `maxFillAmount`. + */ +export function getSampleAmounts(maxFillAmount: BigNumber, numSamples: number, expBase: number = 1): BigNumber[] { + const distribution = [...Array(numSamples)].map((v, i) => new BigNumber(expBase).pow(i)); + const stepSizes = distribution.map(d => d.div(BigNumber.sum(...distribution))); + const amounts = stepSizes.map((s, i) => { + return maxFillAmount + .times(BigNumber.sum(...[0, ...stepSizes.slice(0, i + 1)])) + .integerValue(BigNumber.ROUND_UP); + }); + return amounts; +} + +type BatchedOperationResult = T extends BatchedOperation ? TResult : never; + +/** + * Encapsulates interactions with the `ERC20BridgeSampler` contract. + */ +export class DexOrderSampler { + /** + * Composable operations that can be batched in a single transaction, + * for use with `DexOrderSampler.executeAsync()`. + */ + public static ops = samplerOperations; + private readonly _samplerContract: IERC20BridgeSamplerContract; constructor(samplerContract: IERC20BridgeSamplerContract) { this._samplerContract = samplerContract; } - public async getFillableAmountsAndSampleMarketBuyAsync( - nativeOrders: SignedOrder[], - sampleAmounts: BigNumber[], - sources: ERC20BridgeSource[], - ): Promise<[BigNumber[], DexSample[][]]> { - const signatures = nativeOrders.map(o => o.signature); - const [fillableAmount, rawSamples] = await this._samplerContract - .queryOrdersAndSampleBuys(nativeOrders, signatures, sources.map(s => SOURCE_TO_ADDRESS[s]), sampleAmounts) - .callAsync(); - const quotes = rawSamples.map((rawDexSamples, sourceIdx) => { - const source = sources[sourceIdx]; - return rawDexSamples.map((sample, sampleIdx) => ({ - source, - input: sampleAmounts[sampleIdx], - output: sample, - })); - }); - return [fillableAmount, quotes]; + /* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */ + + // prettier-ignore + public async executeAsync< + T1 + >(...ops: [T1]): Promise<[ + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2 + >(...ops: [T1, T2]): Promise<[ + BatchedOperationResult, + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2, T3 + >(...ops: [T1, T2, T3]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2, T3, T4 + >(...ops: [T1, T2, T3, T4]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2, T3, T4, T5 + >(...ops: [T1, T2, T3, T4, T5]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2, T3, T4, T5, T6 + >(...ops: [T1, T2, T3, T4, T5, T6]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2, T3, T4, T5, T6, T7 + >(...ops: [T1, T2, T3, T4, T5, T6, T7]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult + ]>; + + // prettier-ignore + public async executeAsync< + T1, T2, T3, T4, T5, T6, T7, T8 + >(...ops: [T1, T2, T3, T4, T5, T6, T7, T8]): Promise<[ + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult, + BatchedOperationResult + ]>; + + /** + * Run a series of operations from `DexOrderSampler.ops` in a single transaction. + */ + public async executeAsync(...ops: any[]): Promise { + return this.executeBatchAsync(ops); } - public async getBatchFillableAmountsAndSampleMarketBuyAsync( - nativeOrders: SignedOrder[][], - sampleAmounts: BigNumber[][], - sources: ERC20BridgeSource[], - ): Promise> { - const signatures = nativeOrders.map(o => o.map(i => i.signature)); - const fillableAmountsAndSamples = await this._samplerContract - .queryBatchOrdersAndSampleBuys( - nativeOrders, - signatures, - sources.map(s => SOURCE_TO_ADDRESS[s]), - sampleAmounts, - ) - .callAsync(); - const batchFillableAmountsAndQuotes: Array<[BigNumber[], DexSample[][]]> = []; - fillableAmountsAndSamples.forEach((sampleResult, i) => { - const { tokenAmountsBySource, orderFillableAssetAmounts } = sampleResult; - const quotes = tokenAmountsBySource.map((rawDexSamples, sourceIdx) => { - const source = sources[sourceIdx]; - return rawDexSamples.map((sample, sampleIdx) => ({ - source, - input: sampleAmounts[i][sampleIdx], - output: sample, - })); - }); - batchFillableAmountsAndQuotes.push([orderFillableAssetAmounts, quotes]); - }); - return batchFillableAmountsAndQuotes; - } - - public async getFillableAmountsAndSampleMarketSellAsync( - nativeOrders: SignedOrder[], - sampleAmounts: BigNumber[], - sources: ERC20BridgeSource[], - ): Promise<[BigNumber[], DexSample[][]]> { - const signatures = nativeOrders.map(o => o.signature); - const [fillableAmount, rawSamples] = await this._samplerContract - .queryOrdersAndSampleSells(nativeOrders, signatures, sources.map(s => SOURCE_TO_ADDRESS[s]), sampleAmounts) - .callAsync(); - const quotes = rawSamples.map((rawDexSamples, sourceIdx) => { - const source = sources[sourceIdx]; - return rawDexSamples.map((sample, sampleIdx) => ({ - source, - input: sampleAmounts[sampleIdx], - output: sample, - })); - }); - return [fillableAmount, quotes]; + /** + * Run a series of operations from `DexOrderSampler.ops` in a single transaction. + * Takes an arbitrary length array, but is not typesafe. + */ + public async executeBatchAsync>>(ops: T): Promise { + const callDatas = ops.map(o => o.encodeCall(this._samplerContract)); + const callResults = await this._samplerContract.batchCall(callDatas).callAsync(); + return Promise.all(callResults.map(async (r, i) => ops[i].handleCallResultsAsync(this._samplerContract, r))); } } diff --git a/packages/asset-swapper/test/dex_sampler_test.ts b/packages/asset-swapper/test/dex_sampler_test.ts new file mode 100644 index 0000000000..50db083f51 --- /dev/null +++ b/packages/asset-swapper/test/dex_sampler_test.ts @@ -0,0 +1,357 @@ +import { constants, expect, getRandomFloat, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; +import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; +import { SignedOrder } from '@0x/types'; +import { BigNumber, hexUtils } from '@0x/utils'; +import * as _ from 'lodash'; + +import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler'; +import { ERC20BridgeSource } from '../src/utils/market_operation_utils/types'; + +import { MockSamplerContract } from './utils/mock_sampler_contract'; + +const CHAIN_ID = 1; +// tslint:disable: custom-no-magic-numbers +describe('DexSampler tests', () => { + const MAKER_TOKEN = randomAddress(); + const TAKER_TOKEN = randomAddress(); + const MAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(MAKER_TOKEN); + const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN); + + describe('getSampleAmounts()', () => { + const FILL_AMOUNT = getRandomInteger(1, 1e18); + const NUM_SAMPLES = 16; + + it('generates the correct number of amounts', () => { + const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); + expect(amounts).to.be.length(NUM_SAMPLES); + }); + + it('first amount is nonzero', () => { + const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); + expect(amounts[0]).to.not.bignumber.eq(0); + }); + + it('last amount is the fill amount', () => { + const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); + expect(amounts[NUM_SAMPLES - 1]).to.bignumber.eq(FILL_AMOUNT); + }); + + it('can generate a single amount', () => { + const amounts = getSampleAmounts(FILL_AMOUNT, 1); + expect(amounts).to.be.length(1); + expect(amounts[0]).to.bignumber.eq(FILL_AMOUNT); + }); + + it('generates ascending amounts', () => { + const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); + for (const i of _.times(NUM_SAMPLES).slice(1)) { + const prev = amounts[i - 1]; + const amount = amounts[i]; + expect(prev).to.bignumber.lt(amount); + } + }); + }); + + function createOrder(overrides?: Partial): SignedOrder { + return { + chainId: CHAIN_ID, + exchangeAddress: randomAddress(), + makerAddress: constants.NULL_ADDRESS, + takerAddress: constants.NULL_ADDRESS, + senderAddress: constants.NULL_ADDRESS, + feeRecipientAddress: randomAddress(), + salt: generatePseudoRandomSalt(), + expirationTimeSeconds: getRandomInteger(0, 2 ** 64), + makerAssetData: MAKER_ASSET_DATA, + takerAssetData: TAKER_ASSET_DATA, + makerFeeAssetData: constants.NULL_BYTES, + takerFeeAssetData: constants.NULL_BYTES, + makerAssetAmount: getRandomInteger(1, 1e18), + takerAssetAmount: getRandomInteger(1, 1e18), + makerFee: constants.ZERO_AMOUNT, + takerFee: constants.ZERO_AMOUNT, + signature: hexUtils.random(), + ...overrides, + }; + } + const ORDERS = _.times(4, () => createOrder()); + const SIMPLE_ORDERS = ORDERS.map(o => _.omit(o, ['signature', 'chainId', 'exchangeAddress'])); + + describe('operations', () => { + it('getOrderFillableMakerAmounts()', async () => { + const expectedFillableAmounts = ORDERS.map(() => getRandomInteger(0, 100e18)); + const sampler = new MockSamplerContract({ + getOrderFillableMakerAssetAmounts: (orders, signatures) => { + expect(orders).to.deep.eq(SIMPLE_ORDERS); + expect(signatures).to.deep.eq(ORDERS.map(o => o.signature)); + return expectedFillableAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS), + ); + expect(fillableAmounts).to.deep.eq(expectedFillableAmounts); + }); + + it('getOrderFillableTakerAmounts()', async () => { + const expectedFillableAmounts = ORDERS.map(() => getRandomInteger(0, 100e18)); + const sampler = new MockSamplerContract({ + getOrderFillableTakerAssetAmounts: (orders, signatures) => { + expect(orders).to.deep.eq(SIMPLE_ORDERS); + expect(signatures).to.deep.eq(ORDERS.map(o => o.signature)); + return expectedFillableAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS), + ); + expect(fillableAmounts).to.deep.eq(expectedFillableAmounts); + }); + + it('getKyberSellQuotes()', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const sampler = new MockSamplerContract({ + sampleSellsFromKyberNetwork: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts); + return expectedMakerFillAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getKyberSellQuotes( + expectedMakerToken, + expectedTakerToken, + expectedTakerFillAmounts, + ), + ); + expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); + }); + + it('getEth2DaiSellQuotes()', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const sampler = new MockSamplerContract({ + sampleSellsFromEth2Dai: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts); + return expectedMakerFillAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getEth2DaiSellQuotes( + expectedMakerToken, + expectedTakerToken, + expectedTakerFillAmounts, + ), + ); + expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); + }); + + it('getUniswapSellQuotes()', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const sampler = new MockSamplerContract({ + sampleSellsFromUniswap: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts); + return expectedMakerFillAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getUniswapSellQuotes( + expectedMakerToken, + expectedTakerToken, + expectedTakerFillAmounts, + ), + ); + expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); + }); + + it('getEth2DaiBuyQuotes()', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const sampler = new MockSamplerContract({ + sampleBuysFromEth2Dai: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts); + return expectedTakerFillAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getEth2DaiBuyQuotes( + expectedMakerToken, + expectedTakerToken, + expectedMakerFillAmounts, + ), + ); + expect(fillableAmounts).to.deep.eq(expectedTakerFillAmounts); + }); + + it('getUniswapBuyQuotes()', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10); + const sampler = new MockSamplerContract({ + sampleBuysFromUniswap: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts); + return expectedTakerFillAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getUniswapBuyQuotes( + expectedMakerToken, + expectedTakerToken, + expectedMakerFillAmounts, + ), + ); + expect(fillableAmounts).to.deep.eq(expectedTakerFillAmounts); + }); + + interface RatesBySource { + [src: string]: BigNumber; + } + + it('getSellQuotes()', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const sources = [ERC20BridgeSource.Kyber, ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap]; + const ratesBySource: RatesBySource = { + [ERC20BridgeSource.Kyber]: getRandomFloat(0, 100), + [ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100), + [ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100), + }; + const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3); + const sampler = new MockSamplerContract({ + sampleSellsFromKyberNetwork: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts); + return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Kyber]).integerValue()); + }, + sampleSellsFromUniswap: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts); + return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Uniswap]).integerValue()); + }, + sampleSellsFromEth2Dai: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts); + return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue()); + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [quotes] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getSellQuotes( + sources, + expectedMakerToken, + expectedTakerToken, + expectedTakerFillAmounts, + ), + ); + expect(quotes).to.be.length(sources.length); + const expectedQuotes = sources.map(s => + expectedTakerFillAmounts.map(a => ({ + source: s, + input: a, + output: a.times(ratesBySource[s]).integerValue(), + })), + ); + expect(quotes).to.deep.eq(expectedQuotes); + }); + + it('getBuyQuotes()', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const sources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap]; + const ratesBySource: RatesBySource = { + [ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100), + [ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100), + }; + const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3); + const sampler = new MockSamplerContract({ + sampleBuysFromUniswap: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts); + return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Uniswap]).integerValue()); + }, + sampleBuysFromEth2Dai: (takerToken, makerToken, fillAmounts) => { + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts); + return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue()); + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [quotes] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getBuyQuotes( + sources, + expectedMakerToken, + expectedTakerToken, + expectedMakerFillAmounts, + ), + ); + expect(quotes).to.be.length(sources.length); + const expectedQuotes = sources.map(s => + expectedMakerFillAmounts.map(a => ({ + source: s, + input: a, + output: a.times(ratesBySource[s]).integerValue(), + })), + ); + expect(quotes).to.deep.eq(expectedQuotes); + }); + }); + + describe('batched operations', () => { + it('getOrderFillableMakerAmounts(), getOrderFillableTakerAmounts()', async () => { + const expectedFillableTakerAmounts = ORDERS.map(() => getRandomInteger(0, 100e18)); + const expectedFillableMakerAmounts = ORDERS.map(() => getRandomInteger(0, 100e18)); + const sampler = new MockSamplerContract({ + getOrderFillableMakerAssetAmounts: (orders, signatures) => { + expect(orders).to.deep.eq(SIMPLE_ORDERS); + expect(signatures).to.deep.eq(ORDERS.map(o => o.signature)); + return expectedFillableMakerAmounts; + }, + getOrderFillableTakerAssetAmounts: (orders, signatures) => { + expect(orders).to.deep.eq(SIMPLE_ORDERS); + expect(signatures).to.deep.eq(ORDERS.map(o => o.signature)); + return expectedFillableTakerAmounts; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [fillableMakerAmounts, fillableTakerAmounts] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS), + DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS), + ); + expect(fillableMakerAmounts).to.deep.eq(expectedFillableMakerAmounts); + expect(fillableTakerAmounts).to.deep.eq(expectedFillableTakerAmounts); + }); + }); +}); +// tslint:disable-next-line: max-file-line-count diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index 0145930f09..c591e482de 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -10,23 +10,20 @@ import { } from '@0x/contracts-test-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; -import { Order, SignedOrder } from '@0x/types'; +import { SignedOrder } from '@0x/types'; import { BigNumber, hexUtils } from '@0x/utils'; import * as _ from 'lodash'; import { MarketOperationUtils } from '../src/utils/market_operation_utils/'; import { constants as marketOperationUtilConstants } from '../src/utils/market_operation_utils/constants'; import { DexOrderSampler } from '../src/utils/market_operation_utils/sampler'; -import { ERC20BridgeSource } from '../src/utils/market_operation_utils/types'; +import { DexSample, ERC20BridgeSource } from '../src/utils/market_operation_utils/types'; -import { MockSamplerContract, QueryAndSampleResult } from './utils/mock_sampler_contract'; +const { BUY_SOURCES, SELL_SOURCES } = marketOperationUtilConstants; -const { SOURCE_TO_ADDRESS, BUY_SOURCES, SELL_SOURCES } = marketOperationUtilConstants; - -// Because the bridges and the DEX sources are only deployed on mainnet, tests will resort to using mainnet addresses -const CHAIN_ID = 1; // tslint:disable: custom-no-magic-numbers describe('MarketOperationUtils tests', () => { + const CHAIN_ID = 1; const contractAddresses = getContractAddressesForChainOrThrow(CHAIN_ID); const ETH2DAI_BRIDGE_ADDRESS = contractAddresses.eth2DaiBridge; const KYBER_BRIDGE_ADDRESS = contractAddresses.kyberBridge; @@ -36,10 +33,15 @@ describe('MarketOperationUtils tests', () => { const TAKER_TOKEN = randomAddress(); const MAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(MAKER_TOKEN); const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN); + let originalSamplerOperations: any; - interface RatesBySource { - [source: string]: Numberish[]; - } + before(() => { + originalSamplerOperations = DexOrderSampler.ops; + }); + + after(() => { + DexOrderSampler.ops = originalSamplerOperations; + }); function createOrder(overrides?: Partial): SignedOrder { return { @@ -82,15 +84,6 @@ describe('MarketOperationUtils tests', () => { throw new Error(`Unknown bridge address: ${bridgeAddress}`); } - function getSourceFromAddress(sourceAddress: string): ERC20BridgeSource { - for (const k of Object.keys(SOURCE_TO_ADDRESS)) { - if (SOURCE_TO_ADDRESS[k].toLowerCase() === sourceAddress.toLowerCase()) { - return k as ERC20BridgeSource; - } - } - throw new Error(`Unknown source address: ${sourceAddress}`); - } - function assertSamePrefix(actual: string, expected: string): void { expect(actual.substr(0, expected.length)).to.eq(expected); } @@ -107,7 +100,7 @@ describe('MarketOperationUtils tests', () => { function createOrdersFromBuyRates(makerAssetAmount: BigNumber, rates: Numberish[]): SignedOrder[] { const singleMakerAssetAmount = makerAssetAmount.div(rates.length).integerValue(BigNumber.ROUND_UP); - return (rates as any).map((r: Numberish) => + return rates.map(r => createOrder({ makerAssetAmount: singleMakerAssetAmount, takerAssetAmount: singleMakerAssetAmount.div(r).integerValue(), @@ -115,272 +108,197 @@ describe('MarketOperationUtils tests', () => { ); } - function createSamplerFromSellRates(rates: RatesBySource): MockSamplerContract { - return new MockSamplerContract({ - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => { - const fillableTakerAssetAmounts = orders.map(o => o.takerAssetAmount); - const samplesBySourceIndex = sources.map(s => - fillAmounts.map((fillAmount, idx) => - fillAmount.times(rates[getSourceFromAddress(s)][idx]).integerValue(BigNumber.ROUND_UP), - ), - ); - return [fillableTakerAssetAmounts, samplesBySourceIndex]; - }, - }); - } - - function createSamplerFromBuyRates(rates: RatesBySource): MockSamplerContract { - return new MockSamplerContract({ - queryOrdersAndSampleBuys: (orders, signatures, sources, fillAmounts) => { - const fillableMakerAssetAmounts = orders.map(o => o.makerAssetAmount); - const samplesBySourceIndex = sources.map(s => - fillAmounts.map((fillAmount, idx) => - fillAmount.div(rates[getSourceFromAddress(s)][idx]).integerValue(BigNumber.ROUND_UP), - ), - ); - return [fillableMakerAssetAmounts, samplesBySourceIndex]; - }, - }); - } - - const DUMMY_QUERY_AND_SAMPLE_HANDLER_SELL = ( - orders: Order[], - signatures: string[], - sources: string[], - fillAmounts: BigNumber[], - ): QueryAndSampleResult => [ - orders.map((order: Order) => order.takerAssetAmount), - sources.map(() => fillAmounts.map(() => getRandomInteger(1, 1e18))), - ]; - - const DUMMY_QUERY_AND_SAMPLE_HANDLER_BUY = ( - orders: Order[], - signatures: string[], - sources: string[], - fillAmounts: BigNumber[], - ): QueryAndSampleResult => [ - orders.map((order: Order) => order.makerAssetAmount), - sources.map(() => fillAmounts.map(() => getRandomInteger(1, 1e18))), - ]; - const ORDER_DOMAIN = { exchangeAddress: contractAddresses.exchange, chainId: CHAIN_ID, }; - describe('DexOrderSampler', () => { - describe('getSampleAmounts()', () => { - const FILL_AMOUNT = getRandomInteger(1, 1e18); - const NUM_SAMPLES = 16; + type GetQuotesOperation = (makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => BigNumber[]; - it('generates the correct number of amounts', () => { - const amounts = DexOrderSampler.getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); - expect(amounts).to.be.length(NUM_SAMPLES); - }); - - it('first amount is nonzero', () => { - const amounts = DexOrderSampler.getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); - expect(amounts[0]).to.not.bignumber.eq(0); - }); - - it('last amount is the fill amount', () => { - const amounts = DexOrderSampler.getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); - expect(amounts[NUM_SAMPLES - 1]).to.bignumber.eq(FILL_AMOUNT); - }); - - it('can generate a single amount', () => { - const amounts = DexOrderSampler.getSampleAmounts(FILL_AMOUNT, 1); - expect(amounts).to.be.length(1); - expect(amounts[0]).to.bignumber.eq(FILL_AMOUNT); - }); - - it('generates ascending amounts', () => { - const amounts = DexOrderSampler.getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES); - for (const i of _.times(NUM_SAMPLES).slice(1)) { - const prev = amounts[i - 1]; - const amount = amounts[i]; - expect(prev).to.bignumber.lt(amount); - } - }); - }); - - describe('getFillableAmountsAndSampleMarketOperationAsync()', () => { - const SAMPLE_AMOUNTS = [100, 500, 1000].map(v => new BigNumber(v)); - const ORDERS = _.times(4, () => createOrder()); - - it('makes an eth_call with the correct arguments for a sell', async () => { - const sampler = new MockSamplerContract({ - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => { - expect(orders).to.deep.eq(ORDERS); - expect(signatures).to.deep.eq(ORDERS.map(o => o.signature)); - expect(sources).to.deep.eq(SELL_SOURCES.map(s => SOURCE_TO_ADDRESS[s])); - expect(fillAmounts).to.deep.eq(SAMPLE_AMOUNTS); - return [ - orders.map(() => getRandomInteger(1, 1e18)), - sources.map(() => fillAmounts.map(() => getRandomInteger(1, 1e18))), - ]; - }, - }); - const dexOrderSampler = new DexOrderSampler(sampler); - await dexOrderSampler.getFillableAmountsAndSampleMarketSellAsync(ORDERS, SAMPLE_AMOUNTS, SELL_SOURCES); - }); - - it('makes an eth_call with the correct arguments for a buy', async () => { - const sampler = new MockSamplerContract({ - queryOrdersAndSampleBuys: (orders, signatures, sources, fillAmounts) => { - expect(orders).to.deep.eq(ORDERS); - expect(signatures).to.deep.eq(ORDERS.map(o => o.signature)); - expect(sources).to.deep.eq(BUY_SOURCES.map(s => SOURCE_TO_ADDRESS[s])); - expect(fillAmounts).to.deep.eq(SAMPLE_AMOUNTS); - return [ - orders.map(() => getRandomInteger(1, 1e18)), - sources.map(() => fillAmounts.map(() => getRandomInteger(1, 1e18))), - ]; - }, - }); - const dexOrderSampler = new DexOrderSampler(sampler); - await dexOrderSampler.getFillableAmountsAndSampleMarketBuyAsync(ORDERS, SAMPLE_AMOUNTS, BUY_SOURCES); - }); - - it('returns correct fillable amounts', async () => { - const fillableAmounts = _.times(SAMPLE_AMOUNTS.length, () => getRandomInteger(1, 1e18)); - const sampler = new MockSamplerContract({ - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => [ - fillableAmounts, - sources.map(() => fillAmounts.map(() => getRandomInteger(1, 1e18))), - ], - }); - const dexOrderSampler = new DexOrderSampler(sampler); - const [actualFillableAmounts] = await dexOrderSampler.getFillableAmountsAndSampleMarketSellAsync( - ORDERS, - SAMPLE_AMOUNTS, - SELL_SOURCES, - ); - expect(actualFillableAmounts).to.deep.eq(fillableAmounts); - }); - - it('converts samples to DEX quotes', async () => { - const quotes = SELL_SOURCES.map(source => - SAMPLE_AMOUNTS.map(s => ({ - source, - input: s, - output: getRandomInteger(1, 1e18), - })), - ); - const sampler = new MockSamplerContract({ - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => [ - orders.map(() => getRandomInteger(1, 1e18)), - quotes.map(q => q.map(s => s.output)), - ], - }); - const dexOrderSampler = new DexOrderSampler(sampler); - const [, actualQuotes] = await dexOrderSampler.getFillableAmountsAndSampleMarketSellAsync( - ORDERS, - SAMPLE_AMOUNTS, - SELL_SOURCES, - ); - expect(actualQuotes).to.deep.eq(quotes); - }); - }); - }); - - function createRandomRates(numSamples: number = 32): RatesBySource { - const ALL_SOURCES = [ - ERC20BridgeSource.Native, - ERC20BridgeSource.Eth2Dai, - ERC20BridgeSource.Kyber, - ERC20BridgeSource.Uniswap, - ]; - return _.zipObject( - ALL_SOURCES, - _.times(ALL_SOURCES.length, () => _.fill(new Array(numSamples), getRandomFloat(1e-3, 2))), - ); + function createGetSellQuotesOperationFromRates(rates: Numberish[]): GetQuotesOperation { + return (makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => { + return fillAmounts.map((a, i) => a.times(rates[i]).integerValue()); + }; } + function createGetBuyQuotesOperationFromRates(rates: Numberish[]): GetQuotesOperation { + return (makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => { + return fillAmounts.map((a, i) => a.div(rates[i]).integerValue()); + }; + } + + type GetMultipleQuotesOperation = ( + sources: ERC20BridgeSource[], + makerToken: string, + takerToken: string, + fillAmounts: BigNumber[], + ) => DexSample[][]; + + function createGetMultipleSellQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation { + return (sources: ERC20BridgeSource[], makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => { + return sources.map(s => + fillAmounts.map((a, i) => ({ + source: s, + input: a, + output: a.times(rates[s][i]).integerValue(), + })), + ); + }; + } + + function createGetMultipleBuyQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation { + return (sources: ERC20BridgeSource[], makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => { + return sources.map(s => + fillAmounts.map((a, i) => ({ + source: s, + input: a, + output: a.div(rates[s][i]).integerValue(), + })), + ); + }; + } + + function createDecreasingRates(count: number): BigNumber[] { + const rates: BigNumber[] = []; + const initialRate = getRandomFloat(1e-3, 1e2); + _.times(count, () => getRandomFloat(0.95, 1)).forEach((r, i) => { + const prevRate = i === 0 ? initialRate : rates[i - 1]; + rates.push(prevRate.times(r)); + }); + return rates; + } + + const NUM_SAMPLES = 3; + + interface RatesBySource { + [source: string]: Numberish[]; + } + + const DEFAULT_RATES: RatesBySource = { + [ERC20BridgeSource.Native]: createDecreasingRates(NUM_SAMPLES), + [ERC20BridgeSource.Eth2Dai]: createDecreasingRates(NUM_SAMPLES), + [ERC20BridgeSource.Kyber]: createDecreasingRates(NUM_SAMPLES), + [ERC20BridgeSource.Uniswap]: createDecreasingRates(NUM_SAMPLES), + }; + + function findSourceWithMaxOutput(rates: RatesBySource): ERC20BridgeSource { + const minSourceRates = Object.keys(rates).map(s => _.last(rates[s]) as BigNumber); + const bestSourceRate = BigNumber.max(...minSourceRates); + let source = Object.keys(rates)[_.findIndex(minSourceRates, t => bestSourceRate.eq(t))] as ERC20BridgeSource; + // Native order rates play by different rules. + if (source !== ERC20BridgeSource.Native) { + const nativeTotalRate = BigNumber.sum(...rates[ERC20BridgeSource.Native]).div( + rates[ERC20BridgeSource.Native].length, + ); + if (nativeTotalRate.gt(bestSourceRate)) { + source = ERC20BridgeSource.Native; + } + } + return source; + } + + const DEFAULT_OPS = { + getOrderFillableTakerAmounts(orders: SignedOrder[]): BigNumber[] { + return orders.map(o => o.takerAssetAmount); + }, + getOrderFillableMakerAmounts(orders: SignedOrder[]): BigNumber[] { + return orders.map(o => o.makerAssetAmount); + }, + getKyberSellQuotes: createGetSellQuotesOperationFromRates(DEFAULT_RATES[ERC20BridgeSource.Kyber]), + getUniswapSellQuotes: createGetSellQuotesOperationFromRates(DEFAULT_RATES[ERC20BridgeSource.Uniswap]), + getEth2DaiSellQuotes: createGetSellQuotesOperationFromRates(DEFAULT_RATES[ERC20BridgeSource.Eth2Dai]), + getUniswapBuyQuotes: createGetBuyQuotesOperationFromRates(DEFAULT_RATES[ERC20BridgeSource.Uniswap]), + getEth2DaiBuyQuotes: createGetBuyQuotesOperationFromRates(DEFAULT_RATES[ERC20BridgeSource.Eth2Dai]), + getSellQuotes: createGetMultipleSellQuotesOperationFromRates(DEFAULT_RATES), + getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(DEFAULT_RATES), + }; + + function replaceSamplerOps(ops: Partial = {}): void { + DexOrderSampler.ops = { + ...DEFAULT_OPS, + ...ops, + } as any; + } + + const MOCK_SAMPLER = ({ + async executeAsync(...ops: any[]): Promise { + return ops; + }, + async executeBatchAsync(ops: any[]): Promise { + return ops; + }, + } as any) as DexOrderSampler; + describe('MarketOperationUtils', () => { + let marketOperationUtils: MarketOperationUtils; + + before(async () => { + marketOperationUtils = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN); + }); + describe('getMarketSellOrdersAsync()', () => { const FILL_AMOUNT = getRandomInteger(1, 1e18); - const SOURCE_RATES = createRandomRates(); const ORDERS = createOrdersFromSellRates( FILL_AMOUNT, - _.times(3, () => SOURCE_RATES[ERC20BridgeSource.Native][0]), - ); - const DEFAULT_SAMPLER = createSamplerFromSellRates(SOURCE_RATES); - const DEFAULT_OPTS = { numSamples: 3, runLimit: 0, sampleDistributionBase: 1 }; - const defaultMarketOperationUtils = new MarketOperationUtils( - DEFAULT_SAMPLER, - contractAddresses, - ORDER_DOMAIN, + _.times(NUM_SAMPLES, i => DEFAULT_RATES[ERC20BridgeSource.Native][i]), ); + const DEFAULT_OPTS = { numSamples: NUM_SAMPLES, runLimit: 0, sampleDistributionBase: 1 }; - it('calls `getFillableAmountsAndSampleMarketSellAsync()`', async () => { - let wasCalled = false; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleSells: (...args) => { - wasCalled = true; - return DUMMY_QUERY_AND_SAMPLE_HANDLER_SELL(...args); - }, - }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); - await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, DEFAULT_OPTS); - expect(wasCalled).to.be.true(); + beforeEach(() => { + replaceSamplerOps(); }); it('queries `numSamples` samples', async () => { const numSamples = _.random(1, 16); - let fillAmountsLength = 0; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => { - fillAmountsLength = fillAmounts.length; - return DUMMY_QUERY_AND_SAMPLE_HANDLER_SELL(orders, signatures, sources, fillAmounts); + let actualNumSamples = 0; + replaceSamplerOps({ + getSellQuotes: (sources, makerToken, takerToken, amounts) => { + actualNumSamples = amounts.length; + return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts); }, }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, numSamples, }); - expect(fillAmountsLength).eq(numSamples); + expect(actualNumSamples).eq(numSamples); }); it('polls all DEXes if `excludedSources` is empty', async () => { let sourcesPolled: ERC20BridgeSource[] = []; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => { - sourcesPolled = sources.map(a => getSourceFromAddress(a)); - return DUMMY_QUERY_AND_SAMPLE_HANDLER_SELL(orders, signatures, sources, fillAmounts); + replaceSamplerOps({ + getSellQuotes: (sources, makerToken, takerToken, amounts) => { + sourcesPolled = sources.slice(); + return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts); }, }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, excludedSources: [], }); - expect(sourcesPolled).to.deep.eq(SELL_SOURCES); + expect(sourcesPolled.sort()).to.deep.eq(SELL_SOURCES.slice().sort()); }); it('does not poll DEXes in `excludedSources`', async () => { const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length)); let sourcesPolled: ERC20BridgeSource[] = []; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => { - sourcesPolled = sources.map(a => getSourceFromAddress(a)); - return DUMMY_QUERY_AND_SAMPLE_HANDLER_SELL(orders, signatures, sources, fillAmounts); + replaceSamplerOps({ + getSellQuotes: (sources, makerToken, takerToken, amounts) => { + sourcesPolled = sources.slice(); + return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts); }, }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, excludedSources, }); - expect(sourcesPolled).to.deep.eq(_.without(SELL_SOURCES, ...excludedSources)); + expect(sourcesPolled.sort()).to.deep.eq(_.without(SELL_SOURCES, ...excludedSources).sort()); }); it('returns the most cost-effective single source if `runLimit == 0`', async () => { - const bestRate = BigNumber.max(..._.flatten(Object.values(SOURCE_RATES))); - const bestSource = _.findKey(SOURCE_RATES, ([r]) => new BigNumber(r).eq(bestRate)); + const bestSource = findSourceWithMaxOutput(DEFAULT_RATES); expect(bestSource).to.exist(''); - const improvedOrders = await defaultMarketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { + const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, runLimit: 0, }); @@ -390,7 +308,7 @@ describe('MarketOperationUtils tests', () => { }); it('generates bridge orders with correct asset data', async () => { - const improvedOrders = await defaultMarketOperationUtils.getMarketSellOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync( // Pass in empty orders to prevent native orders from being used. ORDERS.map(o => ({ ...o, makerAssetAmount: constants.ZERO_AMOUNT })), FILL_AMOUNT, @@ -414,7 +332,7 @@ describe('MarketOperationUtils tests', () => { }); it('generates bridge orders with correct taker amount', async () => { - const improvedOrders = await defaultMarketOperationUtils.getMarketSellOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync( // Pass in empty orders to prevent native orders from being used. ORDERS.map(o => ({ ...o, makerAssetAmount: constants.ZERO_AMOUNT })), FILL_AMOUNT, @@ -426,7 +344,7 @@ describe('MarketOperationUtils tests', () => { it('generates bridge orders with max slippage of `bridgeSlippage`', async () => { const bridgeSlippage = _.random(0.1, true); - const improvedOrders = await defaultMarketOperationUtils.getMarketSellOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync( // Pass in empty orders to prevent native orders from being used. ORDERS.map(o => ({ ...o, makerAssetAmount: constants.ZERO_AMOUNT })), FILL_AMOUNT, @@ -435,7 +353,7 @@ describe('MarketOperationUtils tests', () => { expect(improvedOrders).to.not.be.length(0); for (const order of improvedOrders) { const source = getSourceFromAssetData(order.makerAssetData); - const expectedMakerAmount = FILL_AMOUNT.times(SOURCE_RATES[source][0]); + const expectedMakerAmount = FILL_AMOUNT.times(_.last(DEFAULT_RATES[source]) as BigNumber); const slippage = 1 - order.makerAssetAmount.div(expectedMakerAmount.plus(1)).toNumber(); assertRoughlyEquals(slippage, bridgeSlippage, 8); } @@ -450,7 +368,7 @@ describe('MarketOperationUtils tests', () => { makerAssetAmount: dustAmount.times(maxRate.plus(0.01)), takerAssetAmount: dustAmount, }); - const improvedOrders = await defaultMarketOperationUtils.getMarketSellOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync( _.shuffle([dustOrder, ...ORDERS]), FILL_AMOUNT, // Ignore all DEX sources so only native orders are returned. @@ -468,11 +386,9 @@ describe('MarketOperationUtils tests', () => { rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05]; rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05]; rates[ERC20BridgeSource.Kyber] = [0.7, 0.05, 0.05, 0.05]; - const marketOperationUtils = new MarketOperationUtils( - createSamplerFromSellRates(rates), - contractAddresses, - ORDER_DOMAIN, - ); + replaceSamplerOps({ + getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates), + }); const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync( createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]), FILL_AMOUNT, @@ -495,11 +411,9 @@ describe('MarketOperationUtils tests', () => { rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05]; rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05]; rates[ERC20BridgeSource.Kyber] = [0.4, 0.05, 0.05, 0.05]; - const marketOperationUtils = new MarketOperationUtils( - createSamplerFromSellRates(rates), - contractAddresses, - ORDER_DOMAIN, - ); + replaceSamplerOps({ + getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates), + }); const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync( createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]), FILL_AMOUNT, @@ -522,11 +436,9 @@ describe('MarketOperationUtils tests', () => { rates[ERC20BridgeSource.Uniswap] = [0.15, 0.05, 0.05, 0.05]; rates[ERC20BridgeSource.Eth2Dai] = [0.15, 0.05, 0.05, 0.05]; rates[ERC20BridgeSource.Kyber] = [0.7, 0.05, 0.05, 0.05]; - const marketOperationUtils = new MarketOperationUtils( - createSamplerFromSellRates(rates), - contractAddresses, - ORDER_DOMAIN, - ); + replaceSamplerOps({ + getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates), + }); const improvedOrders = await marketOperationUtils.getMarketSellOrdersAsync( createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]), FILL_AMOUNT, @@ -546,61 +458,40 @@ describe('MarketOperationUtils tests', () => { describe('getMarketBuyOrdersAsync()', () => { const FILL_AMOUNT = getRandomInteger(1, 1e18); - const SOURCE_RATES = _.omit(createRandomRates(), [ERC20BridgeSource.Kyber]); const ORDERS = createOrdersFromBuyRates( FILL_AMOUNT, - _.times(3, () => SOURCE_RATES[ERC20BridgeSource.Native][0]), - ); - const DEFAULT_SAMPLER = createSamplerFromBuyRates(SOURCE_RATES); - const DEFAULT_OPTS = { numSamples: 3, runLimit: 0, sampleDistributionBase: 1 }; - const defaultMarketOperationUtils = new MarketOperationUtils( - DEFAULT_SAMPLER, - contractAddresses, - ORDER_DOMAIN, + _.times(NUM_SAMPLES, () => DEFAULT_RATES[ERC20BridgeSource.Native][0]), ); + const DEFAULT_OPTS = { numSamples: NUM_SAMPLES, runLimit: 0, sampleDistributionBase: 1 }; - it('calls `getFillableAmountsAndSampleMarketSellAsync()`', async () => { - let wasCalled = false; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleBuys: (...args) => { - wasCalled = true; - return DUMMY_QUERY_AND_SAMPLE_HANDLER_BUY(...args); - }, - }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); - - await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, DEFAULT_OPTS); - expect(wasCalled).to.be.true(); + beforeEach(() => { + replaceSamplerOps(); }); it('queries `numSamples` samples', async () => { const numSamples = _.random(1, 16); - let fillAmountsLength = 0; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleBuys: (orders, signatures, sources, fillAmounts) => { - fillAmountsLength = fillAmounts.length; - return DUMMY_QUERY_AND_SAMPLE_HANDLER_BUY(orders, signatures, sources, fillAmounts); + let actualNumSamples = 0; + replaceSamplerOps({ + getBuyQuotes: (sources, makerToken, takerToken, amounts) => { + actualNumSamples = amounts.length; + return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts); }, }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); - await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, numSamples, }); - expect(fillAmountsLength).eq(numSamples); + expect(actualNumSamples).eq(numSamples); }); it('polls all DEXes if `excludedSources` is empty', async () => { let sourcesPolled: ERC20BridgeSource[] = []; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleBuys: (orders, signatures, sources, fillAmounts) => { - sourcesPolled = sources.map(a => getSourceFromAddress(a)); - return DUMMY_QUERY_AND_SAMPLE_HANDLER_BUY(orders, signatures, sources, fillAmounts); + replaceSamplerOps({ + getBuyQuotes: (sources, makerToken, takerToken, amounts) => { + sourcesPolled = sources.slice(); + return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts); }, }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); - await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, excludedSources: [], @@ -609,16 +500,14 @@ describe('MarketOperationUtils tests', () => { }); it('does not poll DEXes in `excludedSources`', async () => { - const excludedSources = _.sampleSize(BUY_SOURCES, _.random(1, BUY_SOURCES.length)); + const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length)); let sourcesPolled: ERC20BridgeSource[] = []; - const sampler = new MockSamplerContract({ - queryOrdersAndSampleBuys: (orders, signatures, sources, fillAmounts) => { - sourcesPolled = sources.map(a => getSourceFromAddress(a)); - return DUMMY_QUERY_AND_SAMPLE_HANDLER_BUY(orders, signatures, sources, fillAmounts); + replaceSamplerOps({ + getBuyQuotes: (sources, makerToken, takerToken, amounts) => { + sourcesPolled = sources.slice(); + return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts); }, }); - const marketOperationUtils = new MarketOperationUtils(sampler, contractAddresses, ORDER_DOMAIN); - await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, excludedSources, @@ -627,10 +516,9 @@ describe('MarketOperationUtils tests', () => { }); it('returns the most cost-effective single source if `runLimit == 0`', async () => { - const bestRate = BigNumber.max(..._.flatten(Object.values(SOURCE_RATES))); - const bestSource = _.findKey(SOURCE_RATES, ([r]) => new BigNumber(r).eq(bestRate)); + const bestSource = findSourceWithMaxOutput(_.omit(DEFAULT_RATES, ERC20BridgeSource.Kyber)); expect(bestSource).to.exist(''); - const improvedOrders = await defaultMarketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { + const improvedOrders = await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { ...DEFAULT_OPTS, runLimit: 0, }); @@ -638,8 +526,9 @@ describe('MarketOperationUtils tests', () => { expect(uniqueAssetDatas).to.be.length(1); expect(getSourceFromAssetData(uniqueAssetDatas[0])).to.be.eq(bestSource); }); + it('generates bridge orders with correct asset data', async () => { - const improvedOrders = await defaultMarketOperationUtils.getMarketBuyOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketBuyOrdersAsync( // Pass in empty orders to prevent native orders from being used. ORDERS.map(o => ({ ...o, makerAssetAmount: constants.ZERO_AMOUNT })), FILL_AMOUNT, @@ -663,7 +552,7 @@ describe('MarketOperationUtils tests', () => { }); it('generates bridge orders with correct taker amount', async () => { - const improvedOrders = await defaultMarketOperationUtils.getMarketBuyOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketBuyOrdersAsync( // Pass in empty orders to prevent native orders from being used. ORDERS.map(o => ({ ...o, makerAssetAmount: constants.ZERO_AMOUNT })), FILL_AMOUNT, @@ -675,7 +564,7 @@ describe('MarketOperationUtils tests', () => { it('generates bridge orders with max slippage of `bridgeSlippage`', async () => { const bridgeSlippage = _.random(0.1, true); - const improvedOrders = await defaultMarketOperationUtils.getMarketBuyOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketBuyOrdersAsync( // Pass in empty orders to prevent native orders from being used. ORDERS.map(o => ({ ...o, makerAssetAmount: constants.ZERO_AMOUNT })), FILL_AMOUNT, @@ -684,9 +573,7 @@ describe('MarketOperationUtils tests', () => { expect(improvedOrders).to.not.be.length(0); for (const order of improvedOrders) { const source = getSourceFromAssetData(order.makerAssetData); - const expectedTakerAmount = FILL_AMOUNT.div(SOURCE_RATES[source][0]).integerValue( - BigNumber.ROUND_UP, - ); + const expectedTakerAmount = FILL_AMOUNT.div(_.last(DEFAULT_RATES[source]) as BigNumber); const slippage = order.takerAssetAmount.div(expectedTakerAmount.plus(1)).toNumber() - 1; assertRoughlyEquals(slippage, bridgeSlippage, 8); } @@ -701,7 +588,7 @@ describe('MarketOperationUtils tests', () => { makerAssetAmount: dustAmount, takerAssetAmount: dustAmount.div(maxRate.plus(0.01)).integerValue(BigNumber.ROUND_DOWN), }); - const improvedOrders = await defaultMarketOperationUtils.getMarketBuyOrdersAsync( + const improvedOrders = await marketOperationUtils.getMarketBuyOrdersAsync( _.shuffle([dustOrder, ...ORDERS]), FILL_AMOUNT, // Ignore all DEX sources so only native orders are returned. @@ -718,11 +605,9 @@ describe('MarketOperationUtils tests', () => { rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1]; rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05]; rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05]; - const marketOperationUtils = new MarketOperationUtils( - createSamplerFromBuyRates(rates), - contractAddresses, - ORDER_DOMAIN, - ); + replaceSamplerOps({ + getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates), + }); const improvedOrders = await marketOperationUtils.getMarketBuyOrdersAsync( createOrdersFromBuyRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]), FILL_AMOUNT, diff --git a/packages/asset-swapper/test/swap_quote_calculator_test.ts b/packages/asset-swapper/test/swap_quote_calculator_test.ts index cf8abb4773..d76ec843da 100644 --- a/packages/asset-swapper/test/swap_quote_calculator_test.ts +++ b/packages/asset-swapper/test/swap_quote_calculator_test.ts @@ -8,7 +8,7 @@ import 'mocha'; import { constants } from '../src/constants'; import { CalculateSwapQuoteOpts, SignedOrderWithFillableAmounts } from '../src/types'; -import { MarketOperationUtils } from '../src/utils/market_operation_utils/'; +import { DexOrderSampler, MarketOperationUtils } from '../src/utils/market_operation_utils/'; import { constants as marketOperationUtilConstants } from '../src/utils/market_operation_utils/constants'; import { ProtocolFeeUtils } from '../src/utils/protocol_fee_utils'; import { SwapQuoteCalculator } from '../src/utils/swap_quote_calculator'; @@ -43,27 +43,26 @@ const CALCULATE_SWAP_QUOTE_OPTS: CalculateSwapQuoteOpts = { }, }; -const createSamplerFromSignedOrdersWithFillableAmounts = ( +function createSamplerFromSignedOrdersWithFillableAmounts( signedOrders: SignedOrderWithFillableAmounts[], -): MockSamplerContract => { - const sampler = new MockSamplerContract({ - queryOrdersAndSampleBuys: (orders, signatures, sources, fillAmounts) => { - const fillableAmounts = signatures.map((s: string) => { - const order = (signedOrders.find(o => o.signature === s) as any) as SignedOrderWithFillableAmounts; - return order.fillableMakerAssetAmount; - }); - return [fillableAmounts, sources.map(() => fillAmounts.map(() => constants.ZERO_AMOUNT))]; - }, - queryOrdersAndSampleSells: (orders, signatures, sources, fillAmounts) => { - const fillableAmounts = signatures.map((s: string) => { - const order = (signedOrders.find(o => o.signature === s) as any) as SignedOrderWithFillableAmounts; - return order.fillableTakerAssetAmount; - }); - return [fillableAmounts, sources.map(() => fillAmounts.map(() => constants.ZERO_AMOUNT))]; - }, - }); - return sampler; -}; +): DexOrderSampler { + const sampleDexHandler = (takerToken: string, makerToken: string, amounts: BigNumber[]) => { + return amounts.map(() => constants.ZERO_AMOUNT); + }; + return new DexOrderSampler( + new MockSamplerContract({ + getOrderFillableMakerAssetAmounts: (orders, signatures) => + orders.map((o, i) => signedOrders[i].fillableMakerAssetAmount), + getOrderFillableTakerAssetAmounts: (orders, signatures) => + orders.map((o, i) => signedOrders[i].fillableTakerAssetAmount), + sampleSellsFromEth2Dai: sampleDexHandler, + sampleSellsFromKyberNetwork: sampleDexHandler, + sampleSellsFromUniswap: sampleDexHandler, + sampleBuysFromEth2Dai: sampleDexHandler, + sampleBuysFromUniswap: sampleDexHandler, + }), + ); +} // TODO(dorothy-zbornak): Replace these tests entirely with unit tests because // omg they're a nightmare to maintain. diff --git a/packages/asset-swapper/test/utils/mock_sampler_contract.ts b/packages/asset-swapper/test/utils/mock_sampler_contract.ts index 1b7b2515bf..0ddc580b8f 100644 --- a/packages/asset-swapper/test/utils/mock_sampler_contract.ts +++ b/packages/asset-swapper/test/utils/mock_sampler_contract.ts @@ -2,15 +2,25 @@ import { ContractFunctionObj } from '@0x/base-contract'; import { IERC20BridgeSamplerContract } from '@0x/contract-wrappers'; import { constants } from '@0x/contracts-test-utils'; import { Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, hexUtils } from '@0x/utils'; -export type QueryAndSampleResult = [BigNumber[], BigNumber[][]]; -export type QueryAndSampleHandler = ( +export type GetOrderFillableAssetAmountResult = BigNumber[]; +export type GetOrderFillableAssetAmountHandler = ( orders: Order[], signatures: string[], - sources: string[], - fillAmounts: BigNumber[], -) => QueryAndSampleResult; +) => GetOrderFillableAssetAmountResult; + +export type SampleResults = BigNumber[]; +export type SampleSellsHandler = ( + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], +) => SampleResults; +export type SampleBuysHandler = ( + takerToken: string, + makerToken: string, + makerTokenAmounts: BigNumber[], +) => SampleResults; const DUMMY_PROVIDER = { sendAsync: (...args: any[]): any => { @@ -18,56 +28,156 @@ const DUMMY_PROVIDER = { }, }; +interface Handlers { + getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler; + getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler; + sampleSellsFromKyberNetwork: SampleSellsHandler; + sampleSellsFromEth2Dai: SampleSellsHandler; + sampleSellsFromUniswap: SampleSellsHandler; + sampleBuysFromEth2Dai: SampleBuysHandler; + sampleBuysFromUniswap: SampleBuysHandler; +} + export class MockSamplerContract extends IERC20BridgeSamplerContract { - public readonly queryOrdersAndSampleSellsHandler?: QueryAndSampleHandler; - public readonly queryOrdersAndSampleBuysHandler?: QueryAndSampleHandler; + private readonly _handlers: Partial = {}; - public constructor( - handlers?: Partial<{ - queryOrdersAndSampleSells: QueryAndSampleHandler; - queryOrdersAndSampleBuys: QueryAndSampleHandler; - }>, - ) { + public constructor(handlers: Partial = {}) { super(constants.NULL_ADDRESS, DUMMY_PROVIDER); - const _handlers = { - queryOrdersAndSampleSells: undefined, - queryOrdersAndSampleBuys: undefined, - ...handlers, - }; - this.queryOrdersAndSampleSellsHandler = _handlers.queryOrdersAndSampleSells; - this.queryOrdersAndSampleBuysHandler = _handlers.queryOrdersAndSampleBuys; + this._handlers = handlers; } - public queryOrdersAndSampleSells( - orders: Order[], - signatures: string[], - sources: string[], - fillAmounts: BigNumber[], - ): ContractFunctionObj { + public batchCall(callDatas: string[]): ContractFunctionObj { return { - ...super.queryOrdersAndSampleSells(orders, signatures, sources, fillAmounts), - callAsync: async (...args: any[]): Promise => { - if (!this.queryOrdersAndSampleSellsHandler) { - throw new Error('queryOrdersAndSampleSells handler undefined'); - } - return this.queryOrdersAndSampleSellsHandler(orders, signatures, sources, fillAmounts); - }, + ...super.batchCall(callDatas), + callAsync: async (...callArgs: any[]) => callDatas.map(callData => this._callEncodedFunction(callData)), }; } - public queryOrdersAndSampleBuys( + public getOrderFillableMakerAssetAmounts( orders: Order[], signatures: string[], - sources: string[], - fillAmounts: BigNumber[], - ): ContractFunctionObj { + ): ContractFunctionObj { + return this._wrapCall( + super.getOrderFillableMakerAssetAmounts, + this._handlers.getOrderFillableMakerAssetAmounts, + orders, + signatures, + ); + } + + public getOrderFillableTakerAssetAmounts( + orders: Order[], + signatures: string[], + ): ContractFunctionObj { + return this._wrapCall( + super.getOrderFillableTakerAssetAmounts, + this._handlers.getOrderFillableTakerAssetAmounts, + orders, + signatures, + ); + } + + public sampleSellsFromKyberNetwork( + takerToken: string, + makerToken: string, + takerAssetAmounts: BigNumber[], + ): ContractFunctionObj { + return this._wrapCall( + super.sampleSellsFromKyberNetwork, + this._handlers.sampleSellsFromKyberNetwork, + takerToken, + makerToken, + takerAssetAmounts, + ); + } + + public sampleSellsFromEth2Dai( + takerToken: string, + makerToken: string, + takerAssetAmounts: BigNumber[], + ): ContractFunctionObj { + return this._wrapCall( + super.sampleSellsFromEth2Dai, + this._handlers.sampleSellsFromEth2Dai, + takerToken, + makerToken, + takerAssetAmounts, + ); + } + + public sampleSellsFromUniswap( + takerToken: string, + makerToken: string, + takerAssetAmounts: BigNumber[], + ): ContractFunctionObj { + return this._wrapCall( + super.sampleSellsFromUniswap, + this._handlers.sampleSellsFromUniswap, + takerToken, + makerToken, + takerAssetAmounts, + ); + } + + public sampleBuysFromEth2Dai( + takerToken: string, + makerToken: string, + makerAssetAmounts: BigNumber[], + ): ContractFunctionObj { + return this._wrapCall( + super.sampleBuysFromEth2Dai, + this._handlers.sampleBuysFromEth2Dai, + takerToken, + makerToken, + makerAssetAmounts, + ); + } + + public sampleBuysFromUniswap( + takerToken: string, + makerToken: string, + makerAssetAmounts: BigNumber[], + ): ContractFunctionObj { + return this._wrapCall( + super.sampleBuysFromUniswap, + this._handlers.sampleBuysFromUniswap, + takerToken, + makerToken, + makerAssetAmounts, + ); + } + + private _callEncodedFunction(callData: string): string { + // tslint:disable-next-line: custom-no-magic-numbers + const selector = hexUtils.slice(callData, 0, 4); + for (const [name, handler] of Object.entries(this._handlers)) { + if (handler && this.getSelector(name) === selector) { + const args = this.getABIDecodedTransactionData(name, callData); + const result = (handler as any)(...args); + return this._lookupAbiEncoder(this.getFunctionSignature(name)).encodeReturnValues([result]); + } + } + if (selector === this.getSelector('batchCall')) { + const calls = this.getABIDecodedTransactionData('batchCall', callData); + const results = calls.map(cd => this._callEncodedFunction(cd)); + return this._lookupAbiEncoder(this.getFunctionSignature('batchCall')).encodeReturnValues([results]); + } + throw new Error(`Unkown selector: ${selector}`); + } + + private _wrapCall( + superFn: (this: MockSamplerContract, ...args: TArgs) => ContractFunctionObj, + handler?: (this: MockSamplerContract, ...args: TArgs) => TResult, + // tslint:disable-next-line: trailing-comma + ...args: TArgs + ): ContractFunctionObj { return { - ...super.queryOrdersAndSampleBuys(orders, signatures, sources, fillAmounts), - callAsync: async (...args: any[]): Promise => { - if (!this.queryOrdersAndSampleBuysHandler) { - throw new Error('queryOrdersAndSampleBuys handler undefined'); + ...superFn.call(this, ...args), + callAsync: async (...callArgs: any[]): Promise => { + if (!handler) { + throw new Error(`${superFn.name} handler undefined`); } - return this.queryOrdersAndSampleBuysHandler(orders, signatures, sources, fillAmounts); + return handler.call(this, ...args); }, }; } diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index d7119bc57a..83119a6a74 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -21,6 +21,10 @@ { "note": "Updated Forwarder addresses", "pr": 2469 + }, + { + "note": "Update `ERC20BridgeSampler` address on mainnet and kovan.", + "pr": 2477 } ], "timestamp": 1581204851 diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index b3736b7126..22fc07ae4a 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -20,7 +20,7 @@ "devUtils": "0x161793cdca4ff9e766a706c2c49c36ac1340bbcd", "erc20BridgeProxy": "0x8ed95d1746bf1e4dab58d8ed4724f1ef95b20db0", "uniswapBridge": "0x533344cfdf2a3e911e2cf4c6f5ed08e791f5355f", - "erc20BridgeSampler": "0x38b55fb7b13cbfbf8781e0f11a77b6199ae10a11", + "erc20BridgeSampler": "0x774c53ee7604af93cd3ed1cd25a788a9e0c06fb2", "kyberBridge": "0xf342f3a80fdc9b48713d58fe97e17f5cc764ee62", "eth2DaiBridge": "0xe3379a1956f4a79f39eb2e87bb441419e167538e", "chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438", @@ -108,7 +108,7 @@ "erc20BridgeProxy": "0xfb2dd2a1366de37f7241c83d47da58fd503e2c64", "uniswapBridge": "0x8224aa8fe5c9f07d5a59c735386ff6cc6aaeb568", "eth2DaiBridge": "0x9485d65c6a2fae0d519cced5bd830e57c41998a9", - "erc20BridgeSampler": "0x76a3d21fc9c16afd29eb12a5bdcedd5ddbf24357", + "erc20BridgeSampler": "0xca6485a7d0f1a42192072dff7518324513294adf", "kyberBridge": "0xde7b2747624a647600fdb349184d0448ab954929", "chaiBridge": "0x0000000000000000000000000000000000000000", "dydxBridge": "0x0000000000000000000000000000000000000000", diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json index 27fed82bb5..68a039f84e 100644 --- a/packages/contract-artifacts/CHANGELOG.json +++ b/packages/contract-artifacts/CHANGELOG.json @@ -22,6 +22,10 @@ { "note": "Remove `LibTransactionDecoder` artifact", "pr": 2464 + }, + { + "note": "Update `IERC20BridgeSampler` artifact", + "pr": 2477 } ], "timestamp": 1581204851 diff --git a/packages/contract-artifacts/artifacts/DevUtils.json b/packages/contract-artifacts/artifacts/DevUtils.json index f80842ad18..0d2c11be47 100644 --- a/packages/contract-artifacts/artifacts/DevUtils.json +++ b/packages/contract-artifacts/artifacts/DevUtils.json @@ -828,10 +828,10 @@ }, "evm": { "bytecode": { - "object": "0x60806040523480156200001157600080fd5b5060405162005258380380620052588339810160408190526200003491620003e5565b600080546001600160a01b03199081166001600160a01b0385811691821784556005805490931690851617909155604051630c0e082160e31b8152829185918591906360704108906200009390630f47261b60e41b9060040162000423565b60206040518083038186803b158015620000ac57600080fd5b505afa158015620000c1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620000e79190810190620003b5565b600180546001600160a01b0319166001600160a01b03928316179055604051630c0e082160e31b815290831690636070410890620001319063012b8bc960e11b9060040162000423565b60206040518083038186803b1580156200014a57600080fd5b505afa1580156200015f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620001859190810190620003b5565b600280546001600160a01b0319166001600160a01b03928316179055604051630c0e082160e31b815290831690636070410890620001cf9063a7cb5fb760e01b9060040162000423565b60206040518083038186803b158015620001e857600080fd5b505afa158015620001fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002239190810190620003b5565b600380546001600160a01b0319166001600160a01b03928316179055604051630c0e082160e31b8152908316906360704108906200026d9063619ce88560e11b9060040162000423565b60206040518083038186803b1580156200028657600080fd5b505afa1580156200029b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002c19190810190620003b5565b600480546001600160a01b0319166001600160a01b03928316179055600092508316159050620002f25781620002f4565b305b90506200034f6040518060400160405280600b81526020016a0c1e08141c9bdd1bd8dbdb60aa1b815250604051806040016040528060058152602001640332e302e360dc1b81525085846200035e60201b620029c31760201c565b60065550620004519350505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600060208284031215620003c7578081fd5b81516001600160a01b0381168114620003de578182fd5b9392505050565b60008060408385031215620003f8578081fd5b8251620004058162000438565b6020840151909250620004188162000438565b809150509250929050565b6001600160e01b031991909116815260200190565b6001600160a01b03811681146200044e57600080fd5b50565b614df780620004616000396000f3fe608060405234801561001057600080fd5b506004361061025c5760003560e01c8063a5cd62ba11610145578063d3637905116100bd578063e4e6e7da1161008c578063ee18599711610071578063ee185997146105b5578063ef3bb097146105bd578063ff84e7cc146105c55761025c565b8063e4e6e7da14610572578063e77286eb146105935761025c565b8063d36379051461050a578063d3d862d11461051d578063d469502814610530578063e25cabf7146105505761025c565b8063c26cfecd11610114578063ca49f47c116100f9578063ca49f47c146104c1578063d001c5dc146104e4578063d186037f146104f75761025c565b8063c26cfecd146104b1578063c82037ef146104b95761025c565b8063a5cd62ba14610449578063a6627e9f14610469578063b43cffe11461047c578063bbb2dcf61461048f5761025c565b80637982653e116101d85780639baf2705116101a75780639eadc8351161018c5780639eadc835146103ff578063a070cac814610423578063a0901e51146104365761025c565b80639baf2705146103e25780639cd01605146103f75761025c565b80637982653e1461037b57806379c9c4261461039b5780637d727512146103ae5780638f4ce479146103c15761025c565b80634dfdac201161022f57806363eb39921161021457806363eb3992146103225780636f83188e14610335578063750bdb30146103585761025c565b80634dfdac20146102e2578063590aa875146103025761025c565b806304a5618a146102615780630d7b7d761461028c5780632322cf76146102ad57806346eb65cb146102cd575b600080fd5b61027461026f36600461406c565b6105cd565b60405161028393929190614aee565b60405180910390f35b61029f61029a366004613b30565b610666565b604051610283929190614cd6565b6102c06102bb366004613b30565b610688565b60405161028391906149cb565b6102e06102db36600461406c565b6106b0565b005b6102f56102f0366004613a4b565b610734565b6040516102839190614923565b610315610310366004613a2f565b6107b7565b6040516102839190614b4e565b610315610330366004613b74565b610866565b61034861034336600461406c565b610919565b6040516102839493929190614be2565b61036b61036636600461406c565b6109b9565b6040516102839493929190614a0c565b61038e610389366004614242565b610a4b565b6040516102839190614bcf565b6102c06103a936600461434a565b610afd565b6102c06103bc366004613b30565b610b7e565b6103d46103cf36600461406c565b611474565b6040516102839291906149e9565b6103ea611507565b604051610283919061467e565b6103ea611516565b61041261040d36600461406c565b611525565b604051610283959493929190614a48565b6102c06104313660046142f1565b6115ca565b6102f5610444366004613bf6565b61164b565b61045c610457366004613cc4565b6116c4565b604051610283919061482b565b610315610477366004613bcb565b61177e565b61031561048a366004613a99565b61182e565b6104a261049d36600461406c565b6118e4565b60405161028393929190614b19565b6102c0611974565b6103ea61197a565b6104d46104cf36600461406c565b611989565b6040516102839493929190614aab565b6102f56104f2366004613a4b565b611a1b565b6102c0610505366004613b30565b611a89565b61038e610518366004614242565b612365565b61031561052b366004613d9f565b6123c7565b61054361053e36600461406c565b61241c565b60405161028391906149d4565b61056361055e366004613d48565b6124bf565b60405161028393929190614877565b610585610580366004613a4b565b6125f7565b6040516102839291906149a6565b6105a66105a136600461429a565b612610565b60405161028393929190614c7a565b6103ea612980565b6103ea61298f565b6103ea61299e565b600080600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a856040518263ffffffff1660e01b81526004016106099190614b4e565b60606040518083038186803b15801561062157600080fd5b505af4158015610635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106599190810190613fc2565b9250925092509193909250565b6000806106738484610b7e565b915061067f8484611a89565b90509250929050565b60008060006106978585610666565b915091506106a582826129ad565b925050505b92915050565b6040517f46eb65cb00000000000000000000000000000000000000000000000000000000815273__$d8b635de2bf4a097b4e18b67d0fb68e779$__906346eb65cb90610700908490600401614b4e565b60006040518083038186803b15801561071857600080fd5b505af415801561072c573d6000803e3d6000fd5b505050505b50565b606060008251905080604051908082528060200260200182016040528015610766578160200160208202803883390190505b50915060005b8181146107af576107908585838151811061078357fe5b6020026020010151611a89565b83828151811061079c57fe5b602090810291909101015260010161076c565b505092915050565b6040517f590aa87500000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063590aa8759061080a90859060040161467e565b60006040518083038186803b15801561082257600080fd5b505af4158015610836573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261085e919081019061409f565b90505b919050565b6040517f63eb399200000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__906363eb3992906108bd908790879087906004016147ab565b60006040518083038186803b1580156108d557600080fd5b505af41580156108e9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610911919081019061409f565b949350505050565b60608060608073__$fddee3b26a806429350031cf3481976d2e$__636f83188e866040518263ffffffff1660e01b81526004016109569190614b4e565b60006040518083038186803b15801561096e57600080fd5b505af4158015610982573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa919081019061410d565b93509350935093509193509193565b6000806000606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016109f79190614b4e565b60006040518083038186803b158015610a0f57600080fd5b505af4158015610a23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613e46565b600080546040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91639caa023b91610aad916001600160a01b0316908890889088906004016147dd565b60206040518083038186803b158015610ac557600080fd5b505af4158015610ad9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061091191908101906140ee565b600061091184610b796040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612a1a565b600080610b91838263ffffffff612a2e16565b90506001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415610bec576000610bd884601063ffffffff612a6716565b9050610be48186612a9a565b92505061146d565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415610e055760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401610c589190614b4e565b60606040518083038186803b158015610c7057600080fd5b505af4158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca89190810190613fc2565b6040519194509250606091507f6352211e0000000000000000000000000000000000000000000000000000000090610ce49084906024016149cb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051610d5f9190614662565b600060405180830381855afa9150503d8060008114610d9a576040519150601f19603f3d011682016040523d82523d6000602084013e610d9f565b606091505b50915091506000828015610db4575081516020145b610dbf576000610dd0565b610dd082600c63ffffffff612a6716565b9050896001600160a01b0316816001600160a01b031614610df2576000610df5565b60015b60ff16975050505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156110a157600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b8152600401610e739190614b4e565b60006040518083038186803b158015610e8b57600080fd5b505af4158015610e9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec79190810190613eb0565b5081519296509094509250905060005b81811461109757828181518110610eea57fe5b602002602001015160001415610eff5761108f565b83516060907efdd58e00000000000000000000000000000000000000000000000000000000908b90879085908110610f3357fe5b6020026020010151604051602401610f4c929190614812565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060876001600160a01b031683604051610fc79190614662565b600060405180830381855afa9150503d8060008114611002576040519150601f19603f3d011682016040523d82523d6000602084013e611007565b606091505b5091509150600082801561101c575081516020145b611027576000611038565b61103882600063ffffffff612b9216565b9050600087868151811061104857fe5b6020026020010151828161105857fe5b049050806110745760009b5050505050505050505050506106aa565b8b81108061108057508b155b1561108957809b505b50505050505b600101610ed7565b505050505061146d565b6001600160e01b031981167fc339d10a0000000000000000000000000000000000000000000000000000000014156111d4576040516060907fa85e59e4000000000000000000000000000000000000000000000000000000009061111090869060009081908190602401614b61565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925260045491519092506000916001600160a01b031690611177908490614662565b600060405180830381855afa9150503d80600081146111b2576040519150601f19603f3d011682016040523d82523d6000602084013e6111b7565b606091505b50509050806111c75760006111cb565b6000195b9350505061146d565b6001600160e01b031981167fdc1600f30000000000000000000000000000000000000000000000000000000014156112fd5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016112409190614b4e565b60006040518083038186803b15801561125857600080fd5b505af415801561126c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112949190810190613e46565b5092509250506112a2612b9e565b6001600160a01b0316826001600160a01b03161480156112cf57506005546001600160a01b038281169116145b156112f65760006112e76112e1612bb6565b88612a9a565b90506112f281612bce565b9450505b505061146d565b6001600160e01b031981167f94cfcdd700000000000000000000000000000000000000000000000000000000141561146d5760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b81526004016113699190614b4e565b60006040518083038186803b15801561138157600080fd5b505af4158015611395573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bd9190810190614002565b80519194509250905060005b818114611468578381815181106113dc57fe5b6020026020010151600014156113f157611460565b60006114108985848151811061140357fe5b6020026020010151610b7e565b9050600085838151811061142057fe5b6020026020010151828161143057fe5b049050806114485760009750505050505050506106aa565b87811080611454575087155b1561145d578097505b50505b6001016113c9565b505050505b5092915050565b60008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__638f4ce479846040518263ffffffff1660e01b81526004016114ae9190614b4e565b604080518083038186803b1580156114c557600080fd5b505af41580156114d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114fd9190810190613e0f565b915091505b915091565b6004546001600160a01b031681565b6000546001600160a01b031681565b600080606080606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b81526004016115649190614b4e565b60006040518083038186803b15801561157c57600080fd5b505af4158015611590573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115b89190810190613eb0565b939a9299509097509550909350915050565b6000610911846116466040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612dcc565b6060808251604051908082528060200260200182016040528015611679578160200160208202803883390190505b50905060005b8351811461146d5783818151811061169357fe5b60200260200101516001600160a01b0316318282815181106116b157fe5b602090810291909101015260010161167f565b6000546040517f02cffc4500000000000000000000000000000000000000000000000000000000815260609173__$7a69f714cdde1cb6b62e3c39bc8c94deae$__916302cffc459161172a916001600160a01b03909116908890889088906004016146ac565b60006040518083038186803b15801561174257600080fd5b505af4158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109119190810190613c29565b6040517fa6627e9f00000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063a6627e9f906117d39086908690600401614812565b60006040518083038186803b1580156117eb57600080fd5b505af41580156117ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611827919081019061409f565b9392505050565b6040517fb43cffe100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063b43cffe190611887908890889088908890600401614765565b60006040518083038186803b15801561189f57600080fd5b505af41580156118b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118db919081019061409f565b95945050505050565b600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6856040518263ffffffff1660e01b81526004016119209190614b4e565b60006040518083038186803b15801561193857600080fd5b505af415801561194c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106599190810190614002565b60065481565b6005546001600160a01b031681565b6000806060600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63ca49f47c866040518263ffffffff1660e01b81526004016119c79190614b4e565b60006040518083038186803b1580156119df57600080fd5b505af41580156119f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613f5a565b606060008251905080604051908082528060200260200182016040528015611a4d578160200160208202803883390190505b50915060005b8181146107af57611a6a8585838151811061140357fe5b838281518110611a7657fe5b6020908102919091010152600101611a53565b600080611a9c838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611c075760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b8152600401611b0a9190614b4e565b60006040518083038186803b158015611b2257600080fd5b505af4158015611b36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b5e9190810190614002565b80519194509250905060005b818114611bfc57838181518110611b7d57fe5b602002602001015160001415611b9257611bf4565b6000611ba48985848151811061078357fe5b90506000858381518110611bb457fe5b60200260200101518281611bc457fe5b04905080611bdc5760009750505050505050506106aa565b87811080611be8575087155b15611bf1578097505b50505b600101611b6a565b506106aa9350505050565b6001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415611c68576000611c4c84601063ffffffff612a6716565b600154909150610be490829087906001600160a01b0316612ddb565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415611fb85760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401611cd49190614b4e565b60606040518083038186803b158015611cec57600080fd5b505af4158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d249190810190613fc2565b600254604051929550909350606092507fe985e9c50000000000000000000000000000000000000000000000000000000091611d70918a916001600160a01b0390911690602401614692565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051611deb9190614662565b600060405180830381855afa9150503d8060008114611e26576040519150601f19603f3d011682016040523d82523d6000602084013e611e2b565b606091505b5091509150811580611e3f57508051602014155b80611e5b5750611e5681600063ffffffff612b9216565b600114155b15611fa9576040516060907f081812fc0000000000000000000000000000000000000000000000000000000090611e969087906024016149cb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050856001600160a01b031681604051611f0d9190614662565b600060405180830381855afa9150503d8060008114611f48576040519150601f19603f3d011682016040523d82523d6000602084013e611f4d565b606091505b509093509150828015611f61575081516020145b8015611f9057506002546001600160a01b0316611f8583600c63ffffffff612a6716565b6001600160a01b0316145b611f9b576000611f9e565b60015b60ff16975050611097565b6000199650505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156121df576040517f9eadc83500000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__90639eadc8359061203d908790600401614b4e565b60006040518083038186803b15801561205557600080fd5b505af4158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613eb0565b5050600354604051929450606093507fe985e9c500000000000000000000000000000000000000000000000000000000926120db925089916001600160a01b031690602401614692565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060836001600160a01b0316836040516121569190614662565b600060405180830381855afa9150503d8060008114612191576040519150601f19603f3d011682016040523d82523d6000602084013e612196565b606091505b50915091508180156121a9575080516020145b80156121c557506121c181600063ffffffff612b9216565b6001145b6121d05760006121d4565b6000195b95505050505061146d565b6001600160e01b031981167fc339d10a00000000000000000000000000000000000000000000000000000000141561221b57600019915061146d565b6001600160e01b031981167fdc1600f300000000000000000000000000000000000000000000000000000000141561146d5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016122879190614b4e565b60006040518083038186803b15801561229f57600080fd5b505af41580156122b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122db9190810190613e46565b5092509250506122e9612b9e565b6001600160a01b0316826001600160a01b031614801561231657506005546001600160a01b038281169116145b1561235c57600061233b612328612bb6565b60055489906001600160a01b0316612ddb565b905060001981146123545761234f81612bce565b612358565b6000195b9450505b50505092915050565b600080546040517f8dccde0400000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91638dccde0491610aad916001600160a01b0316908890889088906004016147dd565b6040517fd3d862d100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d3d862d1906117d39086908690600401614936565b6040517fd469502800000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d46950289061246f908590600401614b4e565b60206040518083038186803b15801561248757600080fd5b505af415801561249b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085e9190810190613df4565b60608060606000855190508060405190808252806020026020018201604052801561250457816020015b6124f1613467565b8152602001906001900390816124e95790505b50935080604051908082528060200260200182016040528015612531578160200160208202803883390190505b5092508060405190808252806020026020018201604052801561255e578160200160208202803883390190505b50915060005b8181146125ee5761259b87828151811061257a57fe5b602002602001015187838151811061258e57fe5b6020026020010151612610565b87518890859081106125a957fe5b602002602001018785815181106125bc57fe5b602002602001018786815181106125cf57fe5b9315156020948502919091019093019290925291905252600101612564565b50509250925092565b6060806126048484611a1b565b915061067f8484610734565b612618613467565b600080546040517f9d3fa4b900000000000000000000000000000000000000000000000000000000815282916001600160a01b031690639d3fa4b990612662908890600401614c9e565b60606040518083038186803b15801561267a57600080fd5b505afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126b291908101906141fa565b85516000546040517fa12dcc6f00000000000000000000000000000000000000000000000000000000815292955090916001600160a01b039091169063a12dcc6f906127049089908990600401614cb1565b60206040518083038186803b15801561271c57600080fd5b505afa158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127549190810190613dd4565b9150600061276187612ee5565b90506000612782886101800151896101400151612f0190919063ffffffff16565b156127b7576127b0826127a68a60c001518b60800151612f2690919063ffffffff16565b8a60a00151612f42565b9050612824565b60c08801516127d3576127b08289608001518a60a00151612f42565b60006127e4848a6101800151610688565b905060006127fb848b608001518c60a00151612f42565b90506000612812838c60c001518d60a00151612f42565b905061281e82826129ad565b93505050505b61284861284287604001518a60a00151612f6490919063ffffffff16565b826129ad565b9450600460005460208a01516040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__92639caa023b926128b3926001600160a01b03909216918e91908c906004016147dd565b60206040518083038186803b1580156128cb57600080fd5b505af41580156128df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061290391908101906140ee565b600481111561290e57fe5b1461291a57600061291c565b845b945061292c886101600151612f83565b61293557600094505b60e0880151158015906129535750612951886101a00151612f83565b155b1561295d57600094505b60038651600681111561296c57fe5b1461297657600094505b5050509250925092565b6001546001600160a01b031681565b6002546001600160a01b031681565b6003546001600160a01b031681565b60008183106129bc5781611827565b5090919050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600061182782612a2985613138565b6131b3565b60008160040183511015612a5457612a54612a4f60038551856004016131ed565b61325c565b5001602001516001600160e01b03191690565b60008160140183511015612a8857612a88612a4f60048551856014016131ed565b5001601401516001600160a01b031690565b60405160009081906060906001600160a01b038616907f70a082310000000000000000000000000000000000000000000000000000000090612ae090879060240161467e565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612b339190614662565b600060405180830381855afa9150503d8060008114612b6e576040519150601f19603f3d011682016040523d82523d6000602084013e612b73565b606091505b5091509150818015612b86575080516020145b156107af576106a58160005b60006118278383613264565b736b175474e89094c44da98b954eedeac495271d0f90565b7306af07097c9eeb7fd685c692751d5c66db49c21590565b600080612bd9612bb6565b6001600160a01b0316634ba2363a6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c4b91908101906140d2565b90506000816001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cc29190810190614403565b4211612d4057816001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d0357600080fd5b505af1158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3b9190810190614403565b612db3565b816001600160a01b0316639f678cca6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612db39190810190614403565b9050610911816b033b2e3c9fd0803ce800000086612f42565b600061182782612a298561328e565b60405160009081906060906001600160a01b038716907fdd62ed3e0000000000000000000000000000000000000000000000000000000090612e239088908890602401614692565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612e769190614662565b600060405180830381855afa9150503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5091509150818015612ec9575080516020145b15612edc57612ed9816000612b92565b92505b50509392505050565b6000806000612ef384613347565b9150915061091182826129ad565b6000815183511480156118275750508051602091820120825192909101919091201490565b60008282018381101561182757611827612a4f6000868661338a565b600061091183612f58868563ffffffff6133a916565b9063ffffffff6133da16565b600082821115612f7d57612f7d612a4f6002858561338a565b50900390565b60006020825181612f9057fe5b06600414612fa057506000610861565b6000612fb2838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd70000000000000000000000000000000000000000000000000000000014612fef576001915050610861565b6040517fbbb2dcf600000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063bbb2dcf690613042908790600401614b4e565b60006040518083038186803b15801561305a57600080fd5b505af415801561306e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130969190810190614002565b80519093509150600090505b81811461312c5760006130d260008584815181106130bc57fe5b6020026020010151612a2e90919063ffffffff16565b90506001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415613123576131108483613404565b1561312357600095505050505050610861565b506001016130a2565b50600195945050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc7154150881529485019590955290830191909152948101949094526001600160a01b039091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6060632800659560e01b84848460405160240161320c93929190614bc1565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915290509392505050565b805160208201fd5b6000816020018351101561328557613285612a4f60058551856020016131ed565b50016020015190565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534939092909160208710156132da57fe5b601f1987018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b600080600483610140015151101561336457506000905080611502565b6133778360000151846101400151610b7e565b6114fd8460000151856101400151611a89565b606063e946c1bb60e01b84848460405160240161320c93929190614b9f565b6000826133b8575060006106aa565b828202828482816133c557fe5b041461182757611827612a4f6001868661338a565b6000816133f0576133f0612a4f6003858561338a565b60008284816133fb57fe5b04949350505050565b8151600090600183015b818110156107af5761344f85828151811061342557fe5b602002602001015186868151811061343957fe5b6020026020010151612f0190919063ffffffff16565b1561345f576001925050506106aa565b60010161340e565b6040805160608101909152806000815260006020820181905260409091015290565b80356106aa81614d89565b80516106aa81614d89565b600082601f8301126134af578081fd5b81356134c26134bd82614d0b565b614ce4565b8181529150602080830190848101818402860182018710156134e357600080fd5b60005b848110156114685781356134f981614d89565b845292820192908201906001016134e6565b600082601f83011261351b578081fd5b81356135296134bd82614d0b565b8181529150602080830190840160005b838110156135665761355187602084358901016136fa565b83526020928301929190910190600101613539565b5050505092915050565b600082601f830112613580578081fd5b815161358e6134bd82614d0b565b8181529150602080830190840160005b83811015613566576135b68760208451890101613748565b8352602092830192919091019060010161359e565b600082601f8301126135db578081fd5b81356135e96134bd82614d0b565b8181529150602080830190840160005b8381101561356657613611876020843589010161379d565b835260209283019291909101906001016135f9565b600082601f830112613636578081fd5b81356136446134bd82614d0b565b81815291506020808301908481018184028601820187101561366557600080fd5b60005b8481101561146857813584529282019290820190600101613668565b600082601f830112613694578081fd5b81516136a26134bd82614d0b565b8181529150602080830190848101818402860182018710156136c357600080fd5b60005b84811015611468578151845292820192908201906001016136c6565b80516001600160e01b0319811681146106aa57600080fd5b600082601f83011261370a578081fd5b81356137186134bd82614d2b565b915080825283602082850101111561372f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112613758578081fd5b81516137666134bd82614d2b565b915080825283602082850101111561377d57600080fd5b61146d816020840160208601614d4f565b8051600581106106aa57600080fd5b60006101c08083850312156137b0578182fd5b6137b981614ce4565b9150506137c68383613489565b81526137d58360208401613489565b60208201526137e78360408401613489565b60408201526137f98360608401613489565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff8082111561385b57600080fd5b613867868387016136fa565b8385015261016092508285013591508082111561388357600080fd5b61388f868387016136fa565b838501526101809250828501359150808211156138ab57600080fd5b6138b7868387016136fa565b838501526101a09250828501359150808211156138d357600080fd5b506138e0858286016136fa565b82840152505092915050565b60006101c08083850312156138ff578182fd5b61390881614ce4565b9150506139158383613494565b81526139248360208401613494565b60208201526139368360408401613494565b60408201526139488360608401613494565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156139aa57600080fd5b6139b686838701613748565b838501526101609250828501519150808211156139d257600080fd5b6139de86838701613748565b838501526101809250828501519150808211156139fa57600080fd5b613a0686838701613748565b838501526101a0925082850151915080821115613a2257600080fd5b506138e085828601613748565b600060208284031215613a40578081fd5b813561182781614d89565b60008060408385031215613a5d578081fd5b8235613a6881614d89565b9150602083013567ffffffffffffffff811115613a83578182fd5b613a8f8582860161350b565b9150509250929050565b60008060008060808587031215613aae578182fd5b8435613ab981614d89565b9350602085013567ffffffffffffffff80821115613ad5578384fd5b613ae188838901613626565b94506040870135915080821115613af6578384fd5b613b0288838901613626565b93506060870135915080821115613b17578283fd5b50613b24878288016136fa565b91505092959194509250565b60008060408385031215613b42578182fd5b8235613b4d81614d89565b9150602083013567ffffffffffffffff811115613b68578182fd5b613a8f858286016136fa565b600080600060608486031215613b88578081fd5b8335613b9381614d89565b9250602084013567ffffffffffffffff811115613bae578182fd5b613bba868287016136fa565b925050604084013590509250925092565b60008060408385031215613bdd578182fd5b8235613be881614d89565b946020939093013593505050565b600060208284031215613c07578081fd5b813567ffffffffffffffff811115613c1d578182fd5b6109118482850161349f565b60006020808385031215613c3b578182fd5b825167ffffffffffffffff811115613c51578283fd5b80840185601f820112613c62578384fd5b80519150613c726134bd83614d0b565b8281528381019082850185850284018601891015613c8e578687fd5b8693505b84841015613cb857613ca4898261378e565b835260019390930192918501918501613c92565b50979650505050505050565b600080600060608486031215613cd8578081fd5b833567ffffffffffffffff80821115613cef578283fd5b613cfb878388016135cb565b94506020860135915080821115613d10578283fd5b613d1c8783880161349f565b93506040860135915080821115613d31578283fd5b50613d3e86828701613626565b9150509250925092565b60008060408385031215613d5a578182fd5b823567ffffffffffffffff80821115613d71578384fd5b613d7d868387016135cb565b93506020850135915080821115613d92578283fd5b50613a8f8582860161350b565b60008060408385031215613db1578182fd5b823567ffffffffffffffff80821115613dc8578384fd5b613d7d86838701613626565b600060208284031215613de5578081fd5b81518015158114611827578182fd5b600060208284031215613e05578081fd5b61182783836136e2565b60008060408385031215613e21578182fd5b613e2b84846136e2565b91506020830151613e3b81614d89565b809150509250929050565b60008060008060808587031215613e5b578182fd5b8451613e6681614d9e565b6020860151909450613e7781614d89565b6040860151909350613e8881614d89565b606086015190925067ffffffffffffffff811115613ea4578182fd5b613b2487828801613748565b600080600080600060a08688031215613ec7578283fd5b613ed187876136e2565b94506020860151613ee181614d89565b604087015190945067ffffffffffffffff80821115613efe578485fd5b613f0a89838a01613684565b94506060880151915080821115613f1f578283fd5b613f2b89838a01613684565b93506080880151915080821115613f40578283fd5b50613f4d88828901613748565b9150509295509295909350565b60008060008060808587031215613f6f578182fd5b613f7986866136e2565b93506020850151613f8981614d89565b604086015190935067ffffffffffffffff811115613fa5578283fd5b613fb187828801613748565b606096909601519497939650505050565b600080600060608486031215613fd6578081fd5b613fe085856136e2565b92506020840151613ff081614d89565b80925050604084015190509250925092565b600080600060608486031215614016578081fd5b835161402181614d9e565b602085015190935067ffffffffffffffff8082111561403e578283fd5b61404a87838801613684565b9350604086015191508082111561405f578283fd5b50613d3e86828701613570565b60006020828403121561407d578081fd5b813567ffffffffffffffff811115614093578182fd5b610911848285016136fa565b6000602082840312156140b0578081fd5b815167ffffffffffffffff8111156140c6578182fd5b61091184828501613748565b6000602082840312156140e3578081fd5b815161182781614d89565b6000602082840312156140ff578081fd5b815160058110611827578182fd5b60008060008060808587031215614122578182fd5b845167ffffffffffffffff80821115614139578384fd5b61414588838901613748565b955060209150818701518181111561415b578485fd5b80880189601f82011261416c578586fd5b8051915061417c6134bd83614d0b565b82815284810190828601885b858110156141b15761419f8e8984518801016138ec565b84529287019290870190600101614188565b505060408b01519098509450505050808211156141cc578384fd5b6141d888838901613684565b935060608701519150808211156141ed578283fd5b50613b2487828801613570565b60006060828403121561420b578081fd5b6142156060614ce4565b825160078110614223578283fd5b8152602083810151908201526040928301519281019290925250919050565b600080600060608486031215614256578081fd5b833567ffffffffffffffff81111561426c578182fd5b6142788682870161379d565b935050602084013561428981614d89565b929592945050506040919091013590565b600080604083850312156142ac578182fd5b823567ffffffffffffffff808211156142c3578384fd5b6142cf8683870161379d565b935060208501359150808211156142e4578283fd5b50613a8f858286016136fa565b600080600060608486031215614305578081fd5b833567ffffffffffffffff81111561431b578182fd5b6143278682870161379d565b93505060208401359150604084013561433f81614d89565b809150509250925092565b60008060006060848603121561435e578081fd5b833567ffffffffffffffff80821115614375578283fd5b81860160a08189031215614387578384fd5b61439160a0614ce4565b925080358352602081013560208401526040810135604084015260608101356143b981614d89565b60608401526080810135828111156143cf578485fd5b6143db898284016136fa565b6080850152509194505050602084013591506143fa8560408601613489565b90509250925092565b600060208284031215614414578081fd5b5051919050565b1515815260200190565b6000614431838361453e565b505060600190565b6001600160a01b03169052565b6000815180845260208401935060208301825b828110156144805781516001600160a01b0316865260209586019590910190600101614459565b5093949350505050565b600081518084526020840180819550602083028101915060208501845b848110156144d55782840388526144bf848351614512565b60209889019890945091909101906001016144a7565b50919695505050505050565b6000815180845260208401935060208301825b828110156144805781518652602095860195909101906001016144f4565b6000815180845261452a816020860160208601614d4f565b601f01601f19169290920160200192915050565b80516007811061454a57fe5b825260208181015190830152604090810151910152565b60006101c0614571848451614439565b60208301516145836020860182614439565b5060408301516145966040860182614439565b5060608301516145a96060860182614439565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e085015261010080840151818601525061012080840151818601525061014080840151828287015261460283870182614512565b9150506101609150818401518582038387015261461f8282614512565b92505050610180808401518583038287015261463b8382614512565b9150506101a0915081840151858203838701526146588282614512565b9695505050505050565b60008251614674818460208701614d4f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6000608082016001600160a01b03871683526080602084015280865180835260a08501915060a060208202860101925060208801845b82811015614731577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6087860301845261471c858351614561565b945060209384019391909101906001016146e2565b5050505082810360408401526147478186614446565b838103606085015261475981866144e1565b98975050505050505050565b60006001600160a01b03861682526080602083015261478760808301866144e1565b828103604084015261479981866144e1565b83810360608501526147598186614512565b60006001600160a01b0385168252606060208301526147cd6060830185614512565b9050826040830152949350505050565b60006001600160a01b038087168352608060208401526148006080840187614561565b94166040830152506060015292915050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000918401906040840190835b8181101561486c57835161485881614d7f565b835260209384019390920191600101614845565b509095945050505050565b6000606082016060835280865161488e81846149cb565b9150602088019250835b818110156148bc576148ab838551614425565b602094909401939250600101614898565b505083810360208501526148d081876144e1565b91505082810360408401528084516148e881846149cb565b9150602086019250835b818110156149165761490583855161441b565b6020949094019392506001016148f2565b5090979650505050505050565b60006020825261182760208301846144e1565b60006040825261494960408301856144e1565b602083820381850152818551808452828401915082838202850101838801865b8381101561499757601f19878403018552614985838351614512565b94860194925090850190600101614969565b50909998505050505050505050565b6000604082526149b960408301856144e1565b82810360208401526118db81856144e1565b90815260200190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b60006001600160e01b0319861682526001600160a01b038086166020840152808516604084015250608060608301526146586080830184614512565b60006001600160e01b0319871682526001600160a01b038616602083015260a06040830152614a7a60a08301866144e1565b8281036060840152614a8c81866144e1565b8381036080850152614a9e8186614512565b9998505050505050505050565b60006001600160e01b0319861682526001600160a01b038516602083015260806040830152614add6080830185614512565b905082606083015295945050505050565b6001600160e01b03199390931683526001600160a01b03919091166020830152604082015260600190565b60006001600160e01b03198516825260606020830152614b3c60608301856144e1565b8281036040840152614658818561448a565b6000602082526118276020830184614512565b600060808252614b746080830187614512565b6001600160a01b03958616602084015293909416604082015260ff9190911660609091015292915050565b6060810160048510614bad57fe5b938152602081019290925260409091015290565b6060810160088510614bad57fe5b60208101614bdc83614d7f565b91905290565b600060808252614bf56080830187614512565b602083820381850152818751808452828401915082838202850101838a01865b83811015614c4357601f19878403018552614c31838351614561565b94860194925090850190600101614c15565b50508681036040880152614c57818a6144e1565b9450505050508281036060840152614c6f818561448a565b979650505050505050565b60a08101614c88828661453e565b8360608301528215156080830152949350505050565b6000602082526118276020830184614561565b600060408252614cc46040830185614561565b82810360208401526118db8185614512565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715614d0357600080fd5b604052919050565b600067ffffffffffffffff821115614d21578081fd5b5060209081020190565b600067ffffffffffffffff821115614d41578081fd5b50601f01601f191660200190565b60005b83811015614d6a578181015183820152602001614d52565b83811115614d79576000848401525b50505050565b6005811061073157fe5b6001600160a01b038116811461073157600080fd5b6001600160e01b03198116811461073157600080fdfea365627a7a72315820d5f953a2f0be372b5155353406d20980ed27dc327f638f1b56f5c24fc55036106c6578706572696d656e74616cf564736f6c63430005100040" + "object": "0x60806040523480156200001157600080fd5b5060405162005228380380620052288339810160408190526200003491620003e5565b600080546001600160a01b03199081166001600160a01b0385811691821784556005805490931690851617909155604051630c0e082160e31b8152829185918591906360704108906200009390630f47261b60e41b9060040162000423565b60206040518083038186803b158015620000ac57600080fd5b505afa158015620000c1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620000e79190810190620003b5565b600180546001600160a01b0319166001600160a01b03928316179055604051630c0e082160e31b815290831690636070410890620001319063012b8bc960e11b9060040162000423565b60206040518083038186803b1580156200014a57600080fd5b505afa1580156200015f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620001859190810190620003b5565b600280546001600160a01b0319166001600160a01b03928316179055604051630c0e082160e31b815290831690636070410890620001cf9063a7cb5fb760e01b9060040162000423565b60206040518083038186803b158015620001e857600080fd5b505afa158015620001fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002239190810190620003b5565b600380546001600160a01b0319166001600160a01b03928316179055604051630c0e082160e31b8152908316906360704108906200026d9063619ce88560e11b9060040162000423565b60206040518083038186803b1580156200028657600080fd5b505afa1580156200029b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002c19190810190620003b5565b600480546001600160a01b0319166001600160a01b03928316179055600092508316159050620002f25781620002f4565b305b90506200034f6040518060400160405280600b81526020016a0c1e08141c9bdd1bd8dbdb60aa1b815250604051806040016040528060058152602001640332e302e360dc1b81525085846200035e60201b620029c31760201c565b60065550620004519350505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600060208284031215620003c7578081fd5b81516001600160a01b0381168114620003de578182fd5b9392505050565b60008060408385031215620003f8578081fd5b8251620004058162000438565b6020840151909250620004188162000438565b809150509250929050565b6001600160e01b031991909116815260200190565b6001600160a01b03811681146200044e57600080fd5b50565b614dc780620004616000396000f3fe608060405234801561001057600080fd5b506004361061025c5760003560e01c8063a5cd62ba11610145578063d3637905116100bd578063e4e6e7da1161008c578063ee18599711610071578063ee185997146105b5578063ef3bb097146105bd578063ff84e7cc146105c55761025c565b8063e4e6e7da14610572578063e77286eb146105935761025c565b8063d36379051461050a578063d3d862d11461051d578063d469502814610530578063e25cabf7146105505761025c565b8063c26cfecd11610114578063ca49f47c116100f9578063ca49f47c146104c1578063d001c5dc146104e4578063d186037f146104f75761025c565b8063c26cfecd146104b1578063c82037ef146104b95761025c565b8063a5cd62ba14610449578063a6627e9f14610469578063b43cffe11461047c578063bbb2dcf61461048f5761025c565b80637982653e116101d85780639baf2705116101a75780639eadc8351161018c5780639eadc835146103ff578063a070cac814610423578063a0901e51146104365761025c565b80639baf2705146103e25780639cd01605146103f75761025c565b80637982653e1461037b57806379c9c4261461039b5780637d727512146103ae5780638f4ce479146103c15761025c565b80634dfdac201161022f57806363eb39921161021457806363eb3992146103225780636f83188e14610335578063750bdb30146103585761025c565b80634dfdac20146102e2578063590aa875146103025761025c565b806304a5618a146102615780630d7b7d761461028c5780632322cf76146102ad57806346eb65cb146102cd575b600080fd5b61027461026f36600461406c565b6105cd565b60405161028393929190614abe565b60405180910390f35b61029f61029a366004613b30565b610666565b604051610283929190614ca6565b6102c06102bb366004613b30565b610688565b604051610283919061499b565b6102e06102db36600461406c565b6106b0565b005b6102f56102f0366004613a4b565b610734565b60405161028391906148f3565b610315610310366004613a2f565b6107b7565b6040516102839190614b1e565b610315610330366004613b74565b610866565b61034861034336600461406c565b610919565b6040516102839493929190614bb2565b61036b61036636600461406c565b6109b9565b60405161028394939291906149dc565b61038e610389366004614242565b610a4b565b6040516102839190614b9f565b6102c06103a936600461434a565b610afd565b6102c06103bc366004613b30565b610b7e565b6103d46103cf36600461406c565b611474565b6040516102839291906149b9565b6103ea611507565b604051610283919061465f565b6103ea611516565b61041261040d36600461406c565b611525565b604051610283959493929190614a18565b6102c06104313660046142f1565b6115ca565b6102f5610444366004613bf6565b61164b565b61045c610457366004613cc4565b6116c4565b604051610283919061480c565b610315610477366004613bcb565b61177e565b61031561048a366004613a99565b61182e565b6104a261049d36600461406c565b6118e4565b60405161028393929190614ae9565b6102c0611974565b6103ea61197a565b6104d46104cf36600461406c565b611989565b6040516102839493929190614a7b565b6102f56104f2366004613a4b565b611a1b565b6102c0610505366004613b30565b611a89565b61038e610518366004614242565b612365565b61031561052b366004613d9f565b6123c7565b61054361053e36600461406c565b61241c565b60405161028391906149a4565b61056361055e366004613d48565b6124bf565b60405161028393929190614858565b610585610580366004613a4b565b6125f7565b604051610283929190614976565b6105a66105a136600461429a565b612610565b60405161028393929190614c4a565b6103ea612980565b6103ea61298f565b6103ea61299e565b600080600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a856040518263ffffffff1660e01b81526004016106099190614b1e565b60606040518083038186803b15801561062157600080fd5b505af4158015610635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106599190810190613fc2565b9250925092509193909250565b6000806106738484610b7e565b915061067f8484611a89565b90509250929050565b60008060006106978585610666565b915091506106a582826129ad565b925050505b92915050565b6040517f46eb65cb00000000000000000000000000000000000000000000000000000000815273__$d8b635de2bf4a097b4e18b67d0fb68e779$__906346eb65cb90610700908490600401614b1e565b60006040518083038186803b15801561071857600080fd5b505af415801561072c573d6000803e3d6000fd5b505050505b50565b606060008251905080604051908082528060200260200182016040528015610766578160200160208202803883390190505b50915060005b8181146107af576107908585838151811061078357fe5b6020026020010151611a89565b83828151811061079c57fe5b602090810291909101015260010161076c565b505092915050565b6040517f590aa87500000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063590aa8759061080a90859060040161465f565b60006040518083038186803b15801561082257600080fd5b505af4158015610836573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261085e919081019061409f565b90505b919050565b6040517f63eb399200000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__906363eb3992906108bd9087908790879060040161478c565b60006040518083038186803b1580156108d557600080fd5b505af41580156108e9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610911919081019061409f565b949350505050565b60608060608073__$fddee3b26a806429350031cf3481976d2e$__636f83188e866040518263ffffffff1660e01b81526004016109569190614b1e565b60006040518083038186803b15801561096e57600080fd5b505af4158015610982573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa919081019061410d565b93509350935093509193509193565b6000806000606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016109f79190614b1e565b60006040518083038186803b158015610a0f57600080fd5b505af4158015610a23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613e46565b600080546040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91639caa023b91610aad916001600160a01b0316908890889088906004016147be565b60206040518083038186803b158015610ac557600080fd5b505af4158015610ad9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061091191908101906140ee565b600061091184610b796040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612a1a565b600080610b91838263ffffffff612a2e16565b90506001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415610bec576000610bd884601063ffffffff612a6716565b9050610be48186612a9a565b92505061146d565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415610e055760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401610c589190614b1e565b60606040518083038186803b158015610c7057600080fd5b505af4158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca89190810190613fc2565b6040519194509250606091507f6352211e0000000000000000000000000000000000000000000000000000000090610ce490849060240161499b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051610d5f9190614643565b600060405180830381855afa9150503d8060008114610d9a576040519150601f19603f3d011682016040523d82523d6000602084013e610d9f565b606091505b50915091506000828015610db4575081516020145b610dbf576000610dd0565b610dd082600c63ffffffff612a6716565b9050896001600160a01b0316816001600160a01b031614610df2576000610df5565b60015b60ff16975050505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156110a157600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b8152600401610e739190614b1e565b60006040518083038186803b158015610e8b57600080fd5b505af4158015610e9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec79190810190613eb0565b5081519296509094509250905060005b81811461109757828181518110610eea57fe5b602002602001015160001415610eff5761108f565b83516060907efdd58e00000000000000000000000000000000000000000000000000000000908b90879085908110610f3357fe5b6020026020010151604051602401610f4c9291906147f3565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060876001600160a01b031683604051610fc79190614643565b600060405180830381855afa9150503d8060008114611002576040519150601f19603f3d011682016040523d82523d6000602084013e611007565b606091505b5091509150600082801561101c575081516020145b611027576000611038565b61103882600063ffffffff612b9216565b9050600087868151811061104857fe5b6020026020010151828161105857fe5b049050806110745760009b5050505050505050505050506106aa565b8b81108061108057508b155b1561108957809b505b50505050505b600101610ed7565b505050505061146d565b6001600160e01b031981167fc339d10a0000000000000000000000000000000000000000000000000000000014156111d4576040516060907fa85e59e4000000000000000000000000000000000000000000000000000000009061111090869060009081908190602401614b31565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925260045491519092506000916001600160a01b031690611177908490614643565b600060405180830381855afa9150503d80600081146111b2576040519150601f19603f3d011682016040523d82523d6000602084013e6111b7565b606091505b50509050806111c75760006111cb565b6000195b9350505061146d565b6001600160e01b031981167fdc1600f30000000000000000000000000000000000000000000000000000000014156112fd5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016112409190614b1e565b60006040518083038186803b15801561125857600080fd5b505af415801561126c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112949190810190613e46565b5092509250506112a2612b9e565b6001600160a01b0316826001600160a01b03161480156112cf57506005546001600160a01b038281169116145b156112f65760006112e76112e1612bb6565b88612a9a565b90506112f281612bce565b9450505b505061146d565b6001600160e01b031981167f94cfcdd700000000000000000000000000000000000000000000000000000000141561146d5760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b81526004016113699190614b1e565b60006040518083038186803b15801561138157600080fd5b505af4158015611395573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bd9190810190614002565b80519194509250905060005b818114611468578381815181106113dc57fe5b6020026020010151600014156113f157611460565b60006114108985848151811061140357fe5b6020026020010151610b7e565b9050600085838151811061142057fe5b6020026020010151828161143057fe5b049050806114485760009750505050505050506106aa565b87811080611454575087155b1561145d578097505b50505b6001016113c9565b505050505b5092915050565b60008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__638f4ce479846040518263ffffffff1660e01b81526004016114ae9190614b1e565b604080518083038186803b1580156114c557600080fd5b505af41580156114d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114fd9190810190613e0f565b915091505b915091565b6004546001600160a01b031681565b6000546001600160a01b031681565b600080606080606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b81526004016115649190614b1e565b60006040518083038186803b15801561157c57600080fd5b505af4158015611590573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115b89190810190613eb0565b939a9299509097509550909350915050565b6000610911846116466040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612dcc565b6060808251604051908082528060200260200182016040528015611679578160200160208202803883390190505b50905060005b8351811461146d5783818151811061169357fe5b60200260200101516001600160a01b0316318282815181106116b157fe5b602090810291909101015260010161167f565b6000546040517f02cffc4500000000000000000000000000000000000000000000000000000000815260609173__$7a69f714cdde1cb6b62e3c39bc8c94deae$__916302cffc459161172a916001600160a01b039091169088908890889060040161468d565b60006040518083038186803b15801561174257600080fd5b505af4158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109119190810190613c29565b6040517fa6627e9f00000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063a6627e9f906117d390869086906004016147f3565b60006040518083038186803b1580156117eb57600080fd5b505af41580156117ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611827919081019061409f565b9392505050565b6040517fb43cffe100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063b43cffe190611887908890889088908890600401614746565b60006040518083038186803b15801561189f57600080fd5b505af41580156118b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118db919081019061409f565b95945050505050565b600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6856040518263ffffffff1660e01b81526004016119209190614b1e565b60006040518083038186803b15801561193857600080fd5b505af415801561194c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106599190810190614002565b60065481565b6005546001600160a01b031681565b6000806060600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63ca49f47c866040518263ffffffff1660e01b81526004016119c79190614b1e565b60006040518083038186803b1580156119df57600080fd5b505af41580156119f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613f5a565b606060008251905080604051908082528060200260200182016040528015611a4d578160200160208202803883390190505b50915060005b8181146107af57611a6a8585838151811061140357fe5b838281518110611a7657fe5b6020908102919091010152600101611a53565b600080611a9c838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611c075760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b8152600401611b0a9190614b1e565b60006040518083038186803b158015611b2257600080fd5b505af4158015611b36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b5e9190810190614002565b80519194509250905060005b818114611bfc57838181518110611b7d57fe5b602002602001015160001415611b9257611bf4565b6000611ba48985848151811061078357fe5b90506000858381518110611bb457fe5b60200260200101518281611bc457fe5b04905080611bdc5760009750505050505050506106aa565b87811080611be8575087155b15611bf1578097505b50505b600101611b6a565b506106aa9350505050565b6001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415611c68576000611c4c84601063ffffffff612a6716565b600154909150610be490829087906001600160a01b0316612ddb565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415611fb85760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401611cd49190614b1e565b60606040518083038186803b158015611cec57600080fd5b505af4158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d249190810190613fc2565b600254604051929550909350606092507fe985e9c50000000000000000000000000000000000000000000000000000000091611d70918a916001600160a01b0390911690602401614673565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051611deb9190614643565b600060405180830381855afa9150503d8060008114611e26576040519150601f19603f3d011682016040523d82523d6000602084013e611e2b565b606091505b5091509150811580611e3f57508051602014155b80611e5b5750611e5681600063ffffffff612b9216565b600114155b15611fa9576040516060907f081812fc0000000000000000000000000000000000000000000000000000000090611e9690879060240161499b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050856001600160a01b031681604051611f0d9190614643565b600060405180830381855afa9150503d8060008114611f48576040519150601f19603f3d011682016040523d82523d6000602084013e611f4d565b606091505b509093509150828015611f61575081516020145b8015611f9057506002546001600160a01b0316611f8583600c63ffffffff612a6716565b6001600160a01b0316145b611f9b576000611f9e565b60015b60ff16975050611097565b6000199650505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156121df576040517f9eadc83500000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__90639eadc8359061203d908790600401614b1e565b60006040518083038186803b15801561205557600080fd5b505af4158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613eb0565b5050600354604051929450606093507fe985e9c500000000000000000000000000000000000000000000000000000000926120db925089916001600160a01b031690602401614673565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060836001600160a01b0316836040516121569190614643565b600060405180830381855afa9150503d8060008114612191576040519150601f19603f3d011682016040523d82523d6000602084013e612196565b606091505b50915091508180156121a9575080516020145b80156121c557506121c181600063ffffffff612b9216565b6001145b6121d05760006121d4565b6000195b95505050505061146d565b6001600160e01b031981167fc339d10a00000000000000000000000000000000000000000000000000000000141561221b57600019915061146d565b6001600160e01b031981167fdc1600f300000000000000000000000000000000000000000000000000000000141561146d5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016122879190614b1e565b60006040518083038186803b15801561229f57600080fd5b505af41580156122b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122db9190810190613e46565b5092509250506122e9612b9e565b6001600160a01b0316826001600160a01b031614801561231657506005546001600160a01b038281169116145b1561235c57600061233b612328612bb6565b60055489906001600160a01b0316612ddb565b905060001981146123545761234f81612bce565b612358565b6000195b9450505b50505092915050565b600080546040517f8dccde0400000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91638dccde0491610aad916001600160a01b0316908890889088906004016147be565b6040517fd3d862d100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d3d862d1906117d39086908690600401614906565b6040517fd469502800000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d46950289061246f908590600401614b1e565b60206040518083038186803b15801561248757600080fd5b505af415801561249b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085e9190810190613df4565b60608060606000855190508060405190808252806020026020018201604052801561250457816020015b6124f1613467565b8152602001906001900390816124e95790505b50935080604051908082528060200260200182016040528015612531578160200160208202803883390190505b5092508060405190808252806020026020018201604052801561255e578160200160208202803883390190505b50915060005b8181146125ee5761259b87828151811061257a57fe5b602002602001015187838151811061258e57fe5b6020026020010151612610565b87518890859081106125a957fe5b602002602001018785815181106125bc57fe5b602002602001018786815181106125cf57fe5b9315156020948502919091019093019290925291905252600101612564565b50509250925092565b6060806126048484611a1b565b915061067f8484610734565b612618613467565b600080546040517f9d3fa4b900000000000000000000000000000000000000000000000000000000815282916001600160a01b031690639d3fa4b990612662908890600401614c6e565b60606040518083038186803b15801561267a57600080fd5b505afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126b291908101906141fa565b85516000546040517fa12dcc6f00000000000000000000000000000000000000000000000000000000815292955090916001600160a01b039091169063a12dcc6f906127049089908990600401614c81565b60206040518083038186803b15801561271c57600080fd5b505afa158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127549190810190613dd4565b9150600061276187612ee5565b90506000612782886101800151896101400151612f0190919063ffffffff16565b156127b7576127b0826127a68a60c001518b60800151612f2690919063ffffffff16565b8a60a00151612f42565b9050612824565b60c08801516127d3576127b08289608001518a60a00151612f42565b60006127e4848a6101800151610688565b905060006127fb848b608001518c60a00151612f42565b90506000612812838c60c001518d60a00151612f42565b905061281e82826129ad565b93505050505b61284861284287604001518a60a00151612f6490919063ffffffff16565b826129ad565b9450600460005460208a01516040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__92639caa023b926128b3926001600160a01b03909216918e91908c906004016147be565b60206040518083038186803b1580156128cb57600080fd5b505af41580156128df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061290391908101906140ee565b600481111561290e57fe5b1461291a57600061291c565b845b945061292c886101600151612f83565b61293557600094505b60e0880151158015906129535750612951886101a00151612f83565b155b1561295d57600094505b60038651600681111561296c57fe5b1461297657600094505b5050509250925092565b6001546001600160a01b031681565b6002546001600160a01b031681565b6003546001600160a01b031681565b60008183106129bc5781611827565b5090919050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600061182782612a2985613138565b6131b3565b60008160040183511015612a5457612a54612a4f60038551856004016131ed565b61325c565b5001602001516001600160e01b03191690565b60008160140183511015612a8857612a88612a4f60048551856014016131ed565b5001601401516001600160a01b031690565b60405160009081906060906001600160a01b038616907f70a082310000000000000000000000000000000000000000000000000000000090612ae090879060240161465f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612b339190614643565b600060405180830381855afa9150503d8060008114612b6e576040519150601f19603f3d011682016040523d82523d6000602084013e612b73565b606091505b5091509150818015612b86575080516020145b156107af576106a58160005b60006118278383613264565b736b175474e89094c44da98b954eedeac495271d0f90565b7306af07097c9eeb7fd685c692751d5c66db49c21590565b600080612bd9612bb6565b6001600160a01b0316634ba2363a6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c4b91908101906140d2565b90506000816001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cc29190810190614402565b4211612d4057816001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d0357600080fd5b505af1158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3b9190810190614402565b612db3565b816001600160a01b0316639f678cca6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612db39190810190614402565b9050610911816b033b2e3c9fd0803ce800000086612f42565b600061182782612a298561328e565b60405160009081906060906001600160a01b038716907fdd62ed3e0000000000000000000000000000000000000000000000000000000090612e239088908890602401614673565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612e769190614643565b600060405180830381855afa9150503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5091509150818015612ec9575080516020145b15612edc57612ed9816000612b92565b92505b50509392505050565b6000806000612ef384613347565b9150915061091182826129ad565b6000815183511480156118275750508051602091820120825192909101919091201490565b60008282018381101561182757611827612a4f6000868661338a565b600061091183612f58868563ffffffff6133a916565b9063ffffffff6133da16565b600082821115612f7d57612f7d612a4f6002858561338a565b50900390565b60006020825181612f9057fe5b06600414612fa057506000610861565b6000612fb2838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd70000000000000000000000000000000000000000000000000000000014612fef576001915050610861565b6040517fbbb2dcf600000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063bbb2dcf690613042908790600401614b1e565b60006040518083038186803b15801561305a57600080fd5b505af415801561306e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130969190810190614002565b80519093509150600090505b81811461312c5760006130d260008584815181106130bc57fe5b6020026020010151612a2e90919063ffffffff16565b90506001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415613123576131108483613404565b1561312357600095505050505050610861565b506001016130a2565b50600195945050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc7154150881529485019590955290830191909152948101949094526001600160a01b039091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6060632800659560e01b84848460405160240161320c93929190614b91565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915290509392505050565b805160208201fd5b6000816020018351101561328557613285612a4f60058551856020016131ed565b50016020015190565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534939092909160208710156132da57fe5b601f1987018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b600080600483610140015151101561336457506000905080611502565b6133778360000151846101400151610b7e565b6114fd8460000151856101400151611a89565b606063e946c1bb60e01b84848460405160240161320c93929190614b6f565b6000826133b8575060006106aa565b828202828482816133c557fe5b041461182757611827612a4f6001868661338a565b6000816133f0576133f0612a4f6003858561338a565b60008284816133fb57fe5b04949350505050565b8151600090600183015b818110156107af5761344f85828151811061342557fe5b602002602001015186868151811061343957fe5b6020026020010151612f0190919063ffffffff16565b1561345f576001925050506106aa565b60010161340e565b6040805160608101909152806000815260006020820181905260409091015290565b80356106aa81614d59565b80516106aa81614d59565b600082601f8301126134af578081fd5b81356134c26134bd82614cdb565b614cb4565b8181529150602080830190848101818402860182018710156134e357600080fd5b60005b848110156114685781356134f981614d59565b845292820192908201906001016134e6565b600082601f83011261351b578081fd5b81356135296134bd82614cdb565b8181529150602080830190840160005b838110156135665761355187602084358901016136fa565b83526020928301929190910190600101613539565b5050505092915050565b600082601f830112613580578081fd5b815161358e6134bd82614cdb565b8181529150602080830190840160005b83811015613566576135b68760208451890101613748565b8352602092830192919091019060010161359e565b600082601f8301126135db578081fd5b81356135e96134bd82614cdb565b8181529150602080830190840160005b8381101561356657613611876020843589010161379d565b835260209283019291909101906001016135f9565b600082601f830112613636578081fd5b81356136446134bd82614cdb565b81815291506020808301908481018184028601820187101561366557600080fd5b60005b8481101561146857813584529282019290820190600101613668565b600082601f830112613694578081fd5b81516136a26134bd82614cdb565b8181529150602080830190848101818402860182018710156136c357600080fd5b60005b84811015611468578151845292820192908201906001016136c6565b80516001600160e01b0319811681146106aa57600080fd5b600082601f83011261370a578081fd5b81356137186134bd82614cfb565b915080825283602082850101111561372f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112613758578081fd5b81516137666134bd82614cfb565b915080825283602082850101111561377d57600080fd5b61146d816020840160208601614d1f565b8051600581106106aa57600080fd5b60006101c08083850312156137b0578182fd5b6137b981614cb4565b9150506137c68383613489565b81526137d58360208401613489565b60208201526137e78360408401613489565b60408201526137f98360608401613489565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff8082111561385b57600080fd5b613867868387016136fa565b8385015261016092508285013591508082111561388357600080fd5b61388f868387016136fa565b838501526101809250828501359150808211156138ab57600080fd5b6138b7868387016136fa565b838501526101a09250828501359150808211156138d357600080fd5b506138e0858286016136fa565b82840152505092915050565b60006101c08083850312156138ff578182fd5b61390881614cb4565b9150506139158383613494565b81526139248360208401613494565b60208201526139368360408401613494565b60408201526139488360608401613494565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156139aa57600080fd5b6139b686838701613748565b838501526101609250828501519150808211156139d257600080fd5b6139de86838701613748565b838501526101809250828501519150808211156139fa57600080fd5b613a0686838701613748565b838501526101a0925082850151915080821115613a2257600080fd5b506138e085828601613748565b600060208284031215613a40578081fd5b813561182781614d59565b60008060408385031215613a5d578081fd5b8235613a6881614d59565b9150602083013567ffffffffffffffff811115613a83578182fd5b613a8f8582860161350b565b9150509250929050565b60008060008060808587031215613aae578182fd5b8435613ab981614d59565b9350602085013567ffffffffffffffff80821115613ad5578384fd5b613ae188838901613626565b94506040870135915080821115613af6578384fd5b613b0288838901613626565b93506060870135915080821115613b17578283fd5b50613b24878288016136fa565b91505092959194509250565b60008060408385031215613b42578182fd5b8235613b4d81614d59565b9150602083013567ffffffffffffffff811115613b68578182fd5b613a8f858286016136fa565b600080600060608486031215613b88578081fd5b8335613b9381614d59565b9250602084013567ffffffffffffffff811115613bae578182fd5b613bba868287016136fa565b925050604084013590509250925092565b60008060408385031215613bdd578182fd5b8235613be881614d59565b946020939093013593505050565b600060208284031215613c07578081fd5b813567ffffffffffffffff811115613c1d578182fd5b6109118482850161349f565b60006020808385031215613c3b578182fd5b825167ffffffffffffffff811115613c51578283fd5b80840185601f820112613c62578384fd5b80519150613c726134bd83614cdb565b8281528381019082850185850284018601891015613c8e578687fd5b8693505b84841015613cb857613ca4898261378e565b835260019390930192918501918501613c92565b50979650505050505050565b600080600060608486031215613cd8578081fd5b833567ffffffffffffffff80821115613cef578283fd5b613cfb878388016135cb565b94506020860135915080821115613d10578283fd5b613d1c8783880161349f565b93506040860135915080821115613d31578283fd5b50613d3e86828701613626565b9150509250925092565b60008060408385031215613d5a578182fd5b823567ffffffffffffffff80821115613d71578384fd5b613d7d868387016135cb565b93506020850135915080821115613d92578283fd5b50613a8f8582860161350b565b60008060408385031215613db1578182fd5b823567ffffffffffffffff80821115613dc8578384fd5b613d7d86838701613626565b600060208284031215613de5578081fd5b81518015158114611827578182fd5b600060208284031215613e05578081fd5b61182783836136e2565b60008060408385031215613e21578182fd5b613e2b84846136e2565b91506020830151613e3b81614d59565b809150509250929050565b60008060008060808587031215613e5b578182fd5b8451613e6681614d6e565b6020860151909450613e7781614d59565b6040860151909350613e8881614d59565b606086015190925067ffffffffffffffff811115613ea4578182fd5b613b2487828801613748565b600080600080600060a08688031215613ec7578283fd5b613ed187876136e2565b94506020860151613ee181614d59565b604087015190945067ffffffffffffffff80821115613efe578485fd5b613f0a89838a01613684565b94506060880151915080821115613f1f578283fd5b613f2b89838a01613684565b93506080880151915080821115613f40578283fd5b50613f4d88828901613748565b9150509295509295909350565b60008060008060808587031215613f6f578182fd5b613f7986866136e2565b93506020850151613f8981614d59565b604086015190935067ffffffffffffffff811115613fa5578283fd5b613fb187828801613748565b606096909601519497939650505050565b600080600060608486031215613fd6578081fd5b613fe085856136e2565b92506020840151613ff081614d59565b80925050604084015190509250925092565b600080600060608486031215614016578081fd5b835161402181614d6e565b602085015190935067ffffffffffffffff8082111561403e578283fd5b61404a87838801613684565b9350604086015191508082111561405f578283fd5b50613d3e86828701613570565b60006020828403121561407d578081fd5b813567ffffffffffffffff811115614093578182fd5b610911848285016136fa565b6000602082840312156140b0578081fd5b815167ffffffffffffffff8111156140c6578182fd5b61091184828501613748565b6000602082840312156140e3578081fd5b815161182781614d59565b6000602082840312156140ff578081fd5b815160058110611827578182fd5b60008060008060808587031215614122578182fd5b845167ffffffffffffffff80821115614139578384fd5b61414588838901613748565b955060209150818701518181111561415b578485fd5b80880189601f82011261416c578586fd5b8051915061417c6134bd83614cdb565b82815284810190828601885b858110156141b15761419f8e8984518801016138ec565b84529287019290870190600101614188565b505060408b01519098509450505050808211156141cc578384fd5b6141d888838901613684565b935060608701519150808211156141ed578283fd5b50613b2487828801613570565b60006060828403121561420b578081fd5b6142156060614cb4565b825160078110614223578283fd5b8152602083810151908201526040928301519281019290925250919050565b600080600060608486031215614256578081fd5b833567ffffffffffffffff81111561426c578182fd5b6142788682870161379d565b935050602084013561428981614d59565b929592945050506040919091013590565b600080604083850312156142ac578182fd5b823567ffffffffffffffff808211156142c3578384fd5b6142cf8683870161379d565b935060208501359150808211156142e4578283fd5b50613a8f858286016136fa565b600080600060608486031215614305578081fd5b833567ffffffffffffffff81111561431b578182fd5b6143278682870161379d565b93505060208401359150604084013561433f81614d59565b809150509250925092565b60008060006060848603121561435e578081fd5b833567ffffffffffffffff80821115614375578283fd5b81860160a08189031215614387578384fd5b61439160a0614cb4565b92508035835260208101356020840152604081013560408401526143b88860608301613489565b60608401526080810135828111156143ce578485fd5b6143da898284016136fa565b6080850152509194505050602084013591506143f98560408601613489565b90509250925092565b600060208284031215614413578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208401935060208301825b828110156144615781516001600160a01b031686526020958601959091019060010161443a565b5093949350505050565b600081518084526020840180819550602083028101915060208501845b848110156144b65782840388526144a08483516144f3565b6020988901989094509190910190600101614488565b50919695505050505050565b6000815180845260208401935060208301825b828110156144615781518652602095860195909101906001016144d5565b6000815180845261450b816020860160208601614d1f565b601f01601f19169290920160200192915050565b80516007811061452b57fe5b825260208181015190830152604090810151910152565b60006101c061455284845161441a565b6020830151614564602086018261441a565b506040830151614577604086018261441a565b50606083015161458a606086018261441a565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e08501526101008084015181860152506101208084015181860152506101408084015182828701526145e3838701826144f3565b9150506101609150818401518582038387015261460082826144f3565b92505050610180808401518583038287015261461c83826144f3565b9150506101a09150818401518582038387015261463982826144f3565b9695505050505050565b60008251614655818460208701614d1f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6000608082016001600160a01b03871683526080602084015280865180835260a08501915060a060208202860101925060208801845b82811015614712577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608786030184526146fd858351614542565b945060209384019391909101906001016146c3565b5050505082810360408401526147288186614427565b838103606085015261473a81866144c2565b98975050505050505050565b60006001600160a01b03861682526080602083015261476860808301866144c2565b828103604084015261477a81866144c2565b838103606085015261473a81866144f3565b60006001600160a01b0385168252606060208301526147ae60608301856144f3565b9050826040830152949350505050565b60006001600160a01b038087168352608060208401526147e16080840187614542565b94166040830152506060015292915050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000918401906040840190835b8181101561484d57835161483981614d4f565b835260209384019390920191600101614826565b509095945050505050565b606080825284519082018190526000906020906080840190828801845b8281101561489b5761488884835161451f565b6060939093019290840190600101614875565b505050838103828501526148af81876144c2565b84810360408601528551808252908301915082860190845b818110156148e55782511515845292840192918401916001016148c7565b509198975050505050505050565b60006020825261182760208301846144c2565b60006040825261491960408301856144c2565b602083820381850152818551808452828401915082838202850101838801865b8381101561496757601f198784030185526149558383516144f3565b94860194925090850190600101614939565b50909998505050505050505050565b60006040825261498960408301856144c2565b82810360208401526118db81856144c2565b90815260200190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b60006001600160e01b0319861682526001600160a01b0380861660208401528085166040840152506080606083015261463960808301846144f3565b60006001600160e01b0319871682526001600160a01b038616602083015260a06040830152614a4a60a08301866144c2565b8281036060840152614a5c81866144c2565b8381036080850152614a6e81866144f3565b9998505050505050505050565b60006001600160e01b0319861682526001600160a01b038516602083015260806040830152614aad60808301856144f3565b905082606083015295945050505050565b6001600160e01b03199390931683526001600160a01b03919091166020830152604082015260600190565b60006001600160e01b03198516825260606020830152614b0c60608301856144c2565b8281036040840152614639818561446b565b60006020825261182760208301846144f3565b600060808252614b4460808301876144f3565b6001600160a01b03958616602084015293909416604082015260ff9190911660609091015292915050565b6060810160048510614b7d57fe5b938152602081019290925260409091015290565b6060810160088510614b7d57fe5b60208101614bac83614d4f565b91905290565b600060808252614bc560808301876144f3565b602083820381850152818751808452828401915082838202850101838a01865b83811015614c1357601f19878403018552614c01838351614542565b94860194925090850190600101614be5565b50508681036040880152614c27818a6144c2565b9450505050508281036060840152614c3f818561446b565b979650505050505050565b60a08101614c58828661451f565b8360608301528215156080830152949350505050565b6000602082526118276020830184614542565b600060408252614c946040830185614542565b82810360208401526118db81856144f3565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715614cd357600080fd5b604052919050565b600067ffffffffffffffff821115614cf1578081fd5b5060209081020190565b600067ffffffffffffffff821115614d11578081fd5b50601f01601f191660200190565b60005b83811015614d3a578181015183820152602001614d22565b83811115614d49576000848401525b50505050565b6005811061073157fe5b6001600160a01b038116811461073157600080fd5b6001600160e01b03198116811461073157600080fdfea365627a7a72315820d5f953a2f0be372b5155353406d20980ed27dc327f638f1b56f5c24fc55036106c6578706572696d656e74616cf564736f6c63430005100040" }, "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b506004361061025c5760003560e01c8063a5cd62ba11610145578063d3637905116100bd578063e4e6e7da1161008c578063ee18599711610071578063ee185997146105b5578063ef3bb097146105bd578063ff84e7cc146105c55761025c565b8063e4e6e7da14610572578063e77286eb146105935761025c565b8063d36379051461050a578063d3d862d11461051d578063d469502814610530578063e25cabf7146105505761025c565b8063c26cfecd11610114578063ca49f47c116100f9578063ca49f47c146104c1578063d001c5dc146104e4578063d186037f146104f75761025c565b8063c26cfecd146104b1578063c82037ef146104b95761025c565b8063a5cd62ba14610449578063a6627e9f14610469578063b43cffe11461047c578063bbb2dcf61461048f5761025c565b80637982653e116101d85780639baf2705116101a75780639eadc8351161018c5780639eadc835146103ff578063a070cac814610423578063a0901e51146104365761025c565b80639baf2705146103e25780639cd01605146103f75761025c565b80637982653e1461037b57806379c9c4261461039b5780637d727512146103ae5780638f4ce479146103c15761025c565b80634dfdac201161022f57806363eb39921161021457806363eb3992146103225780636f83188e14610335578063750bdb30146103585761025c565b80634dfdac20146102e2578063590aa875146103025761025c565b806304a5618a146102615780630d7b7d761461028c5780632322cf76146102ad57806346eb65cb146102cd575b600080fd5b61027461026f36600461406c565b6105cd565b60405161028393929190614aee565b60405180910390f35b61029f61029a366004613b30565b610666565b604051610283929190614cd6565b6102c06102bb366004613b30565b610688565b60405161028391906149cb565b6102e06102db36600461406c565b6106b0565b005b6102f56102f0366004613a4b565b610734565b6040516102839190614923565b610315610310366004613a2f565b6107b7565b6040516102839190614b4e565b610315610330366004613b74565b610866565b61034861034336600461406c565b610919565b6040516102839493929190614be2565b61036b61036636600461406c565b6109b9565b6040516102839493929190614a0c565b61038e610389366004614242565b610a4b565b6040516102839190614bcf565b6102c06103a936600461434a565b610afd565b6102c06103bc366004613b30565b610b7e565b6103d46103cf36600461406c565b611474565b6040516102839291906149e9565b6103ea611507565b604051610283919061467e565b6103ea611516565b61041261040d36600461406c565b611525565b604051610283959493929190614a48565b6102c06104313660046142f1565b6115ca565b6102f5610444366004613bf6565b61164b565b61045c610457366004613cc4565b6116c4565b604051610283919061482b565b610315610477366004613bcb565b61177e565b61031561048a366004613a99565b61182e565b6104a261049d36600461406c565b6118e4565b60405161028393929190614b19565b6102c0611974565b6103ea61197a565b6104d46104cf36600461406c565b611989565b6040516102839493929190614aab565b6102f56104f2366004613a4b565b611a1b565b6102c0610505366004613b30565b611a89565b61038e610518366004614242565b612365565b61031561052b366004613d9f565b6123c7565b61054361053e36600461406c565b61241c565b60405161028391906149d4565b61056361055e366004613d48565b6124bf565b60405161028393929190614877565b610585610580366004613a4b565b6125f7565b6040516102839291906149a6565b6105a66105a136600461429a565b612610565b60405161028393929190614c7a565b6103ea612980565b6103ea61298f565b6103ea61299e565b600080600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a856040518263ffffffff1660e01b81526004016106099190614b4e565b60606040518083038186803b15801561062157600080fd5b505af4158015610635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106599190810190613fc2565b9250925092509193909250565b6000806106738484610b7e565b915061067f8484611a89565b90509250929050565b60008060006106978585610666565b915091506106a582826129ad565b925050505b92915050565b6040517f46eb65cb00000000000000000000000000000000000000000000000000000000815273__$d8b635de2bf4a097b4e18b67d0fb68e779$__906346eb65cb90610700908490600401614b4e565b60006040518083038186803b15801561071857600080fd5b505af415801561072c573d6000803e3d6000fd5b505050505b50565b606060008251905080604051908082528060200260200182016040528015610766578160200160208202803883390190505b50915060005b8181146107af576107908585838151811061078357fe5b6020026020010151611a89565b83828151811061079c57fe5b602090810291909101015260010161076c565b505092915050565b6040517f590aa87500000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063590aa8759061080a90859060040161467e565b60006040518083038186803b15801561082257600080fd5b505af4158015610836573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261085e919081019061409f565b90505b919050565b6040517f63eb399200000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__906363eb3992906108bd908790879087906004016147ab565b60006040518083038186803b1580156108d557600080fd5b505af41580156108e9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610911919081019061409f565b949350505050565b60608060608073__$fddee3b26a806429350031cf3481976d2e$__636f83188e866040518263ffffffff1660e01b81526004016109569190614b4e565b60006040518083038186803b15801561096e57600080fd5b505af4158015610982573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa919081019061410d565b93509350935093509193509193565b6000806000606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016109f79190614b4e565b60006040518083038186803b158015610a0f57600080fd5b505af4158015610a23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613e46565b600080546040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91639caa023b91610aad916001600160a01b0316908890889088906004016147dd565b60206040518083038186803b158015610ac557600080fd5b505af4158015610ad9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061091191908101906140ee565b600061091184610b796040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612a1a565b600080610b91838263ffffffff612a2e16565b90506001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415610bec576000610bd884601063ffffffff612a6716565b9050610be48186612a9a565b92505061146d565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415610e055760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401610c589190614b4e565b60606040518083038186803b158015610c7057600080fd5b505af4158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca89190810190613fc2565b6040519194509250606091507f6352211e0000000000000000000000000000000000000000000000000000000090610ce49084906024016149cb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051610d5f9190614662565b600060405180830381855afa9150503d8060008114610d9a576040519150601f19603f3d011682016040523d82523d6000602084013e610d9f565b606091505b50915091506000828015610db4575081516020145b610dbf576000610dd0565b610dd082600c63ffffffff612a6716565b9050896001600160a01b0316816001600160a01b031614610df2576000610df5565b60015b60ff16975050505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156110a157600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b8152600401610e739190614b4e565b60006040518083038186803b158015610e8b57600080fd5b505af4158015610e9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec79190810190613eb0565b5081519296509094509250905060005b81811461109757828181518110610eea57fe5b602002602001015160001415610eff5761108f565b83516060907efdd58e00000000000000000000000000000000000000000000000000000000908b90879085908110610f3357fe5b6020026020010151604051602401610f4c929190614812565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060876001600160a01b031683604051610fc79190614662565b600060405180830381855afa9150503d8060008114611002576040519150601f19603f3d011682016040523d82523d6000602084013e611007565b606091505b5091509150600082801561101c575081516020145b611027576000611038565b61103882600063ffffffff612b9216565b9050600087868151811061104857fe5b6020026020010151828161105857fe5b049050806110745760009b5050505050505050505050506106aa565b8b81108061108057508b155b1561108957809b505b50505050505b600101610ed7565b505050505061146d565b6001600160e01b031981167fc339d10a0000000000000000000000000000000000000000000000000000000014156111d4576040516060907fa85e59e4000000000000000000000000000000000000000000000000000000009061111090869060009081908190602401614b61565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925260045491519092506000916001600160a01b031690611177908490614662565b600060405180830381855afa9150503d80600081146111b2576040519150601f19603f3d011682016040523d82523d6000602084013e6111b7565b606091505b50509050806111c75760006111cb565b6000195b9350505061146d565b6001600160e01b031981167fdc1600f30000000000000000000000000000000000000000000000000000000014156112fd5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016112409190614b4e565b60006040518083038186803b15801561125857600080fd5b505af415801561126c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112949190810190613e46565b5092509250506112a2612b9e565b6001600160a01b0316826001600160a01b03161480156112cf57506005546001600160a01b038281169116145b156112f65760006112e76112e1612bb6565b88612a9a565b90506112f281612bce565b9450505b505061146d565b6001600160e01b031981167f94cfcdd700000000000000000000000000000000000000000000000000000000141561146d5760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b81526004016113699190614b4e565b60006040518083038186803b15801561138157600080fd5b505af4158015611395573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bd9190810190614002565b80519194509250905060005b818114611468578381815181106113dc57fe5b6020026020010151600014156113f157611460565b60006114108985848151811061140357fe5b6020026020010151610b7e565b9050600085838151811061142057fe5b6020026020010151828161143057fe5b049050806114485760009750505050505050506106aa565b87811080611454575087155b1561145d578097505b50505b6001016113c9565b505050505b5092915050565b60008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__638f4ce479846040518263ffffffff1660e01b81526004016114ae9190614b4e565b604080518083038186803b1580156114c557600080fd5b505af41580156114d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114fd9190810190613e0f565b915091505b915091565b6004546001600160a01b031681565b6000546001600160a01b031681565b600080606080606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b81526004016115649190614b4e565b60006040518083038186803b15801561157c57600080fd5b505af4158015611590573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115b89190810190613eb0565b939a9299509097509550909350915050565b6000610911846116466040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612dcc565b6060808251604051908082528060200260200182016040528015611679578160200160208202803883390190505b50905060005b8351811461146d5783818151811061169357fe5b60200260200101516001600160a01b0316318282815181106116b157fe5b602090810291909101015260010161167f565b6000546040517f02cffc4500000000000000000000000000000000000000000000000000000000815260609173__$7a69f714cdde1cb6b62e3c39bc8c94deae$__916302cffc459161172a916001600160a01b03909116908890889088906004016146ac565b60006040518083038186803b15801561174257600080fd5b505af4158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109119190810190613c29565b6040517fa6627e9f00000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063a6627e9f906117d39086908690600401614812565b60006040518083038186803b1580156117eb57600080fd5b505af41580156117ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611827919081019061409f565b9392505050565b6040517fb43cffe100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063b43cffe190611887908890889088908890600401614765565b60006040518083038186803b15801561189f57600080fd5b505af41580156118b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118db919081019061409f565b95945050505050565b600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6856040518263ffffffff1660e01b81526004016119209190614b4e565b60006040518083038186803b15801561193857600080fd5b505af415801561194c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106599190810190614002565b60065481565b6005546001600160a01b031681565b6000806060600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63ca49f47c866040518263ffffffff1660e01b81526004016119c79190614b4e565b60006040518083038186803b1580156119df57600080fd5b505af41580156119f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613f5a565b606060008251905080604051908082528060200260200182016040528015611a4d578160200160208202803883390190505b50915060005b8181146107af57611a6a8585838151811061140357fe5b838281518110611a7657fe5b6020908102919091010152600101611a53565b600080611a9c838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611c075760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b8152600401611b0a9190614b4e565b60006040518083038186803b158015611b2257600080fd5b505af4158015611b36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b5e9190810190614002565b80519194509250905060005b818114611bfc57838181518110611b7d57fe5b602002602001015160001415611b9257611bf4565b6000611ba48985848151811061078357fe5b90506000858381518110611bb457fe5b60200260200101518281611bc457fe5b04905080611bdc5760009750505050505050506106aa565b87811080611be8575087155b15611bf1578097505b50505b600101611b6a565b506106aa9350505050565b6001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415611c68576000611c4c84601063ffffffff612a6716565b600154909150610be490829087906001600160a01b0316612ddb565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415611fb85760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401611cd49190614b4e565b60606040518083038186803b158015611cec57600080fd5b505af4158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d249190810190613fc2565b600254604051929550909350606092507fe985e9c50000000000000000000000000000000000000000000000000000000091611d70918a916001600160a01b0390911690602401614692565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051611deb9190614662565b600060405180830381855afa9150503d8060008114611e26576040519150601f19603f3d011682016040523d82523d6000602084013e611e2b565b606091505b5091509150811580611e3f57508051602014155b80611e5b5750611e5681600063ffffffff612b9216565b600114155b15611fa9576040516060907f081812fc0000000000000000000000000000000000000000000000000000000090611e969087906024016149cb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050856001600160a01b031681604051611f0d9190614662565b600060405180830381855afa9150503d8060008114611f48576040519150601f19603f3d011682016040523d82523d6000602084013e611f4d565b606091505b509093509150828015611f61575081516020145b8015611f9057506002546001600160a01b0316611f8583600c63ffffffff612a6716565b6001600160a01b0316145b611f9b576000611f9e565b60015b60ff16975050611097565b6000199650505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156121df576040517f9eadc83500000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__90639eadc8359061203d908790600401614b4e565b60006040518083038186803b15801561205557600080fd5b505af4158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613eb0565b5050600354604051929450606093507fe985e9c500000000000000000000000000000000000000000000000000000000926120db925089916001600160a01b031690602401614692565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060836001600160a01b0316836040516121569190614662565b600060405180830381855afa9150503d8060008114612191576040519150601f19603f3d011682016040523d82523d6000602084013e612196565b606091505b50915091508180156121a9575080516020145b80156121c557506121c181600063ffffffff612b9216565b6001145b6121d05760006121d4565b6000195b95505050505061146d565b6001600160e01b031981167fc339d10a00000000000000000000000000000000000000000000000000000000141561221b57600019915061146d565b6001600160e01b031981167fdc1600f300000000000000000000000000000000000000000000000000000000141561146d5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016122879190614b4e565b60006040518083038186803b15801561229f57600080fd5b505af41580156122b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122db9190810190613e46565b5092509250506122e9612b9e565b6001600160a01b0316826001600160a01b031614801561231657506005546001600160a01b038281169116145b1561235c57600061233b612328612bb6565b60055489906001600160a01b0316612ddb565b905060001981146123545761234f81612bce565b612358565b6000195b9450505b50505092915050565b600080546040517f8dccde0400000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91638dccde0491610aad916001600160a01b0316908890889088906004016147dd565b6040517fd3d862d100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d3d862d1906117d39086908690600401614936565b6040517fd469502800000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d46950289061246f908590600401614b4e565b60206040518083038186803b15801561248757600080fd5b505af415801561249b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085e9190810190613df4565b60608060606000855190508060405190808252806020026020018201604052801561250457816020015b6124f1613467565b8152602001906001900390816124e95790505b50935080604051908082528060200260200182016040528015612531578160200160208202803883390190505b5092508060405190808252806020026020018201604052801561255e578160200160208202803883390190505b50915060005b8181146125ee5761259b87828151811061257a57fe5b602002602001015187838151811061258e57fe5b6020026020010151612610565b87518890859081106125a957fe5b602002602001018785815181106125bc57fe5b602002602001018786815181106125cf57fe5b9315156020948502919091019093019290925291905252600101612564565b50509250925092565b6060806126048484611a1b565b915061067f8484610734565b612618613467565b600080546040517f9d3fa4b900000000000000000000000000000000000000000000000000000000815282916001600160a01b031690639d3fa4b990612662908890600401614c9e565b60606040518083038186803b15801561267a57600080fd5b505afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126b291908101906141fa565b85516000546040517fa12dcc6f00000000000000000000000000000000000000000000000000000000815292955090916001600160a01b039091169063a12dcc6f906127049089908990600401614cb1565b60206040518083038186803b15801561271c57600080fd5b505afa158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127549190810190613dd4565b9150600061276187612ee5565b90506000612782886101800151896101400151612f0190919063ffffffff16565b156127b7576127b0826127a68a60c001518b60800151612f2690919063ffffffff16565b8a60a00151612f42565b9050612824565b60c08801516127d3576127b08289608001518a60a00151612f42565b60006127e4848a6101800151610688565b905060006127fb848b608001518c60a00151612f42565b90506000612812838c60c001518d60a00151612f42565b905061281e82826129ad565b93505050505b61284861284287604001518a60a00151612f6490919063ffffffff16565b826129ad565b9450600460005460208a01516040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__92639caa023b926128b3926001600160a01b03909216918e91908c906004016147dd565b60206040518083038186803b1580156128cb57600080fd5b505af41580156128df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061290391908101906140ee565b600481111561290e57fe5b1461291a57600061291c565b845b945061292c886101600151612f83565b61293557600094505b60e0880151158015906129535750612951886101a00151612f83565b155b1561295d57600094505b60038651600681111561296c57fe5b1461297657600094505b5050509250925092565b6001546001600160a01b031681565b6002546001600160a01b031681565b6003546001600160a01b031681565b60008183106129bc5781611827565b5090919050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600061182782612a2985613138565b6131b3565b60008160040183511015612a5457612a54612a4f60038551856004016131ed565b61325c565b5001602001516001600160e01b03191690565b60008160140183511015612a8857612a88612a4f60048551856014016131ed565b5001601401516001600160a01b031690565b60405160009081906060906001600160a01b038616907f70a082310000000000000000000000000000000000000000000000000000000090612ae090879060240161467e565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612b339190614662565b600060405180830381855afa9150503d8060008114612b6e576040519150601f19603f3d011682016040523d82523d6000602084013e612b73565b606091505b5091509150818015612b86575080516020145b156107af576106a58160005b60006118278383613264565b736b175474e89094c44da98b954eedeac495271d0f90565b7306af07097c9eeb7fd685c692751d5c66db49c21590565b600080612bd9612bb6565b6001600160a01b0316634ba2363a6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c4b91908101906140d2565b90506000816001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cc29190810190614403565b4211612d4057816001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d0357600080fd5b505af1158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3b9190810190614403565b612db3565b816001600160a01b0316639f678cca6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612db39190810190614403565b9050610911816b033b2e3c9fd0803ce800000086612f42565b600061182782612a298561328e565b60405160009081906060906001600160a01b038716907fdd62ed3e0000000000000000000000000000000000000000000000000000000090612e239088908890602401614692565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612e769190614662565b600060405180830381855afa9150503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5091509150818015612ec9575080516020145b15612edc57612ed9816000612b92565b92505b50509392505050565b6000806000612ef384613347565b9150915061091182826129ad565b6000815183511480156118275750508051602091820120825192909101919091201490565b60008282018381101561182757611827612a4f6000868661338a565b600061091183612f58868563ffffffff6133a916565b9063ffffffff6133da16565b600082821115612f7d57612f7d612a4f6002858561338a565b50900390565b60006020825181612f9057fe5b06600414612fa057506000610861565b6000612fb2838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd70000000000000000000000000000000000000000000000000000000014612fef576001915050610861565b6040517fbbb2dcf600000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063bbb2dcf690613042908790600401614b4e565b60006040518083038186803b15801561305a57600080fd5b505af415801561306e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130969190810190614002565b80519093509150600090505b81811461312c5760006130d260008584815181106130bc57fe5b6020026020010151612a2e90919063ffffffff16565b90506001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415613123576131108483613404565b1561312357600095505050505050610861565b506001016130a2565b50600195945050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc7154150881529485019590955290830191909152948101949094526001600160a01b039091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6060632800659560e01b84848460405160240161320c93929190614bc1565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915290509392505050565b805160208201fd5b6000816020018351101561328557613285612a4f60058551856020016131ed565b50016020015190565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534939092909160208710156132da57fe5b601f1987018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b600080600483610140015151101561336457506000905080611502565b6133778360000151846101400151610b7e565b6114fd8460000151856101400151611a89565b606063e946c1bb60e01b84848460405160240161320c93929190614b9f565b6000826133b8575060006106aa565b828202828482816133c557fe5b041461182757611827612a4f6001868661338a565b6000816133f0576133f0612a4f6003858561338a565b60008284816133fb57fe5b04949350505050565b8151600090600183015b818110156107af5761344f85828151811061342557fe5b602002602001015186868151811061343957fe5b6020026020010151612f0190919063ffffffff16565b1561345f576001925050506106aa565b60010161340e565b6040805160608101909152806000815260006020820181905260409091015290565b80356106aa81614d89565b80516106aa81614d89565b600082601f8301126134af578081fd5b81356134c26134bd82614d0b565b614ce4565b8181529150602080830190848101818402860182018710156134e357600080fd5b60005b848110156114685781356134f981614d89565b845292820192908201906001016134e6565b600082601f83011261351b578081fd5b81356135296134bd82614d0b565b8181529150602080830190840160005b838110156135665761355187602084358901016136fa565b83526020928301929190910190600101613539565b5050505092915050565b600082601f830112613580578081fd5b815161358e6134bd82614d0b565b8181529150602080830190840160005b83811015613566576135b68760208451890101613748565b8352602092830192919091019060010161359e565b600082601f8301126135db578081fd5b81356135e96134bd82614d0b565b8181529150602080830190840160005b8381101561356657613611876020843589010161379d565b835260209283019291909101906001016135f9565b600082601f830112613636578081fd5b81356136446134bd82614d0b565b81815291506020808301908481018184028601820187101561366557600080fd5b60005b8481101561146857813584529282019290820190600101613668565b600082601f830112613694578081fd5b81516136a26134bd82614d0b565b8181529150602080830190848101818402860182018710156136c357600080fd5b60005b84811015611468578151845292820192908201906001016136c6565b80516001600160e01b0319811681146106aa57600080fd5b600082601f83011261370a578081fd5b81356137186134bd82614d2b565b915080825283602082850101111561372f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112613758578081fd5b81516137666134bd82614d2b565b915080825283602082850101111561377d57600080fd5b61146d816020840160208601614d4f565b8051600581106106aa57600080fd5b60006101c08083850312156137b0578182fd5b6137b981614ce4565b9150506137c68383613489565b81526137d58360208401613489565b60208201526137e78360408401613489565b60408201526137f98360608401613489565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff8082111561385b57600080fd5b613867868387016136fa565b8385015261016092508285013591508082111561388357600080fd5b61388f868387016136fa565b838501526101809250828501359150808211156138ab57600080fd5b6138b7868387016136fa565b838501526101a09250828501359150808211156138d357600080fd5b506138e0858286016136fa565b82840152505092915050565b60006101c08083850312156138ff578182fd5b61390881614ce4565b9150506139158383613494565b81526139248360208401613494565b60208201526139368360408401613494565b60408201526139488360608401613494565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156139aa57600080fd5b6139b686838701613748565b838501526101609250828501519150808211156139d257600080fd5b6139de86838701613748565b838501526101809250828501519150808211156139fa57600080fd5b613a0686838701613748565b838501526101a0925082850151915080821115613a2257600080fd5b506138e085828601613748565b600060208284031215613a40578081fd5b813561182781614d89565b60008060408385031215613a5d578081fd5b8235613a6881614d89565b9150602083013567ffffffffffffffff811115613a83578182fd5b613a8f8582860161350b565b9150509250929050565b60008060008060808587031215613aae578182fd5b8435613ab981614d89565b9350602085013567ffffffffffffffff80821115613ad5578384fd5b613ae188838901613626565b94506040870135915080821115613af6578384fd5b613b0288838901613626565b93506060870135915080821115613b17578283fd5b50613b24878288016136fa565b91505092959194509250565b60008060408385031215613b42578182fd5b8235613b4d81614d89565b9150602083013567ffffffffffffffff811115613b68578182fd5b613a8f858286016136fa565b600080600060608486031215613b88578081fd5b8335613b9381614d89565b9250602084013567ffffffffffffffff811115613bae578182fd5b613bba868287016136fa565b925050604084013590509250925092565b60008060408385031215613bdd578182fd5b8235613be881614d89565b946020939093013593505050565b600060208284031215613c07578081fd5b813567ffffffffffffffff811115613c1d578182fd5b6109118482850161349f565b60006020808385031215613c3b578182fd5b825167ffffffffffffffff811115613c51578283fd5b80840185601f820112613c62578384fd5b80519150613c726134bd83614d0b565b8281528381019082850185850284018601891015613c8e578687fd5b8693505b84841015613cb857613ca4898261378e565b835260019390930192918501918501613c92565b50979650505050505050565b600080600060608486031215613cd8578081fd5b833567ffffffffffffffff80821115613cef578283fd5b613cfb878388016135cb565b94506020860135915080821115613d10578283fd5b613d1c8783880161349f565b93506040860135915080821115613d31578283fd5b50613d3e86828701613626565b9150509250925092565b60008060408385031215613d5a578182fd5b823567ffffffffffffffff80821115613d71578384fd5b613d7d868387016135cb565b93506020850135915080821115613d92578283fd5b50613a8f8582860161350b565b60008060408385031215613db1578182fd5b823567ffffffffffffffff80821115613dc8578384fd5b613d7d86838701613626565b600060208284031215613de5578081fd5b81518015158114611827578182fd5b600060208284031215613e05578081fd5b61182783836136e2565b60008060408385031215613e21578182fd5b613e2b84846136e2565b91506020830151613e3b81614d89565b809150509250929050565b60008060008060808587031215613e5b578182fd5b8451613e6681614d9e565b6020860151909450613e7781614d89565b6040860151909350613e8881614d89565b606086015190925067ffffffffffffffff811115613ea4578182fd5b613b2487828801613748565b600080600080600060a08688031215613ec7578283fd5b613ed187876136e2565b94506020860151613ee181614d89565b604087015190945067ffffffffffffffff80821115613efe578485fd5b613f0a89838a01613684565b94506060880151915080821115613f1f578283fd5b613f2b89838a01613684565b93506080880151915080821115613f40578283fd5b50613f4d88828901613748565b9150509295509295909350565b60008060008060808587031215613f6f578182fd5b613f7986866136e2565b93506020850151613f8981614d89565b604086015190935067ffffffffffffffff811115613fa5578283fd5b613fb187828801613748565b606096909601519497939650505050565b600080600060608486031215613fd6578081fd5b613fe085856136e2565b92506020840151613ff081614d89565b80925050604084015190509250925092565b600080600060608486031215614016578081fd5b835161402181614d9e565b602085015190935067ffffffffffffffff8082111561403e578283fd5b61404a87838801613684565b9350604086015191508082111561405f578283fd5b50613d3e86828701613570565b60006020828403121561407d578081fd5b813567ffffffffffffffff811115614093578182fd5b610911848285016136fa565b6000602082840312156140b0578081fd5b815167ffffffffffffffff8111156140c6578182fd5b61091184828501613748565b6000602082840312156140e3578081fd5b815161182781614d89565b6000602082840312156140ff578081fd5b815160058110611827578182fd5b60008060008060808587031215614122578182fd5b845167ffffffffffffffff80821115614139578384fd5b61414588838901613748565b955060209150818701518181111561415b578485fd5b80880189601f82011261416c578586fd5b8051915061417c6134bd83614d0b565b82815284810190828601885b858110156141b15761419f8e8984518801016138ec565b84529287019290870190600101614188565b505060408b01519098509450505050808211156141cc578384fd5b6141d888838901613684565b935060608701519150808211156141ed578283fd5b50613b2487828801613570565b60006060828403121561420b578081fd5b6142156060614ce4565b825160078110614223578283fd5b8152602083810151908201526040928301519281019290925250919050565b600080600060608486031215614256578081fd5b833567ffffffffffffffff81111561426c578182fd5b6142788682870161379d565b935050602084013561428981614d89565b929592945050506040919091013590565b600080604083850312156142ac578182fd5b823567ffffffffffffffff808211156142c3578384fd5b6142cf8683870161379d565b935060208501359150808211156142e4578283fd5b50613a8f858286016136fa565b600080600060608486031215614305578081fd5b833567ffffffffffffffff81111561431b578182fd5b6143278682870161379d565b93505060208401359150604084013561433f81614d89565b809150509250925092565b60008060006060848603121561435e578081fd5b833567ffffffffffffffff80821115614375578283fd5b81860160a08189031215614387578384fd5b61439160a0614ce4565b925080358352602081013560208401526040810135604084015260608101356143b981614d89565b60608401526080810135828111156143cf578485fd5b6143db898284016136fa565b6080850152509194505050602084013591506143fa8560408601613489565b90509250925092565b600060208284031215614414578081fd5b5051919050565b1515815260200190565b6000614431838361453e565b505060600190565b6001600160a01b03169052565b6000815180845260208401935060208301825b828110156144805781516001600160a01b0316865260209586019590910190600101614459565b5093949350505050565b600081518084526020840180819550602083028101915060208501845b848110156144d55782840388526144bf848351614512565b60209889019890945091909101906001016144a7565b50919695505050505050565b6000815180845260208401935060208301825b828110156144805781518652602095860195909101906001016144f4565b6000815180845261452a816020860160208601614d4f565b601f01601f19169290920160200192915050565b80516007811061454a57fe5b825260208181015190830152604090810151910152565b60006101c0614571848451614439565b60208301516145836020860182614439565b5060408301516145966040860182614439565b5060608301516145a96060860182614439565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e085015261010080840151818601525061012080840151818601525061014080840151828287015261460283870182614512565b9150506101609150818401518582038387015261461f8282614512565b92505050610180808401518583038287015261463b8382614512565b9150506101a0915081840151858203838701526146588282614512565b9695505050505050565b60008251614674818460208701614d4f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6000608082016001600160a01b03871683526080602084015280865180835260a08501915060a060208202860101925060208801845b82811015614731577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6087860301845261471c858351614561565b945060209384019391909101906001016146e2565b5050505082810360408401526147478186614446565b838103606085015261475981866144e1565b98975050505050505050565b60006001600160a01b03861682526080602083015261478760808301866144e1565b828103604084015261479981866144e1565b83810360608501526147598186614512565b60006001600160a01b0385168252606060208301526147cd6060830185614512565b9050826040830152949350505050565b60006001600160a01b038087168352608060208401526148006080840187614561565b94166040830152506060015292915050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000918401906040840190835b8181101561486c57835161485881614d7f565b835260209384019390920191600101614845565b509095945050505050565b6000606082016060835280865161488e81846149cb565b9150602088019250835b818110156148bc576148ab838551614425565b602094909401939250600101614898565b505083810360208501526148d081876144e1565b91505082810360408401528084516148e881846149cb565b9150602086019250835b818110156149165761490583855161441b565b6020949094019392506001016148f2565b5090979650505050505050565b60006020825261182760208301846144e1565b60006040825261494960408301856144e1565b602083820381850152818551808452828401915082838202850101838801865b8381101561499757601f19878403018552614985838351614512565b94860194925090850190600101614969565b50909998505050505050505050565b6000604082526149b960408301856144e1565b82810360208401526118db81856144e1565b90815260200190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b60006001600160e01b0319861682526001600160a01b038086166020840152808516604084015250608060608301526146586080830184614512565b60006001600160e01b0319871682526001600160a01b038616602083015260a06040830152614a7a60a08301866144e1565b8281036060840152614a8c81866144e1565b8381036080850152614a9e8186614512565b9998505050505050505050565b60006001600160e01b0319861682526001600160a01b038516602083015260806040830152614add6080830185614512565b905082606083015295945050505050565b6001600160e01b03199390931683526001600160a01b03919091166020830152604082015260600190565b60006001600160e01b03198516825260606020830152614b3c60608301856144e1565b8281036040840152614658818561448a565b6000602082526118276020830184614512565b600060808252614b746080830187614512565b6001600160a01b03958616602084015293909416604082015260ff9190911660609091015292915050565b6060810160048510614bad57fe5b938152602081019290925260409091015290565b6060810160088510614bad57fe5b60208101614bdc83614d7f565b91905290565b600060808252614bf56080830187614512565b602083820381850152818751808452828401915082838202850101838a01865b83811015614c4357601f19878403018552614c31838351614561565b94860194925090850190600101614c15565b50508681036040880152614c57818a6144e1565b9450505050508281036060840152614c6f818561448a565b979650505050505050565b60a08101614c88828661453e565b8360608301528215156080830152949350505050565b6000602082526118276020830184614561565b600060408252614cc46040830185614561565b82810360208401526118db8185614512565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715614d0357600080fd5b604052919050565b600067ffffffffffffffff821115614d21578081fd5b5060209081020190565b600067ffffffffffffffff821115614d41578081fd5b50601f01601f191660200190565b60005b83811015614d6a578181015183820152602001614d52565b83811115614d79576000848401525b50505050565b6005811061073157fe5b6001600160a01b038116811461073157600080fd5b6001600160e01b03198116811461073157600080fdfea365627a7a72315820d5f953a2f0be372b5155353406d20980ed27dc327f638f1b56f5c24fc55036106c6578706572696d656e74616cf564736f6c63430005100040" + "object": "0x608060405234801561001057600080fd5b506004361061025c5760003560e01c8063a5cd62ba11610145578063d3637905116100bd578063e4e6e7da1161008c578063ee18599711610071578063ee185997146105b5578063ef3bb097146105bd578063ff84e7cc146105c55761025c565b8063e4e6e7da14610572578063e77286eb146105935761025c565b8063d36379051461050a578063d3d862d11461051d578063d469502814610530578063e25cabf7146105505761025c565b8063c26cfecd11610114578063ca49f47c116100f9578063ca49f47c146104c1578063d001c5dc146104e4578063d186037f146104f75761025c565b8063c26cfecd146104b1578063c82037ef146104b95761025c565b8063a5cd62ba14610449578063a6627e9f14610469578063b43cffe11461047c578063bbb2dcf61461048f5761025c565b80637982653e116101d85780639baf2705116101a75780639eadc8351161018c5780639eadc835146103ff578063a070cac814610423578063a0901e51146104365761025c565b80639baf2705146103e25780639cd01605146103f75761025c565b80637982653e1461037b57806379c9c4261461039b5780637d727512146103ae5780638f4ce479146103c15761025c565b80634dfdac201161022f57806363eb39921161021457806363eb3992146103225780636f83188e14610335578063750bdb30146103585761025c565b80634dfdac20146102e2578063590aa875146103025761025c565b806304a5618a146102615780630d7b7d761461028c5780632322cf76146102ad57806346eb65cb146102cd575b600080fd5b61027461026f36600461406c565b6105cd565b60405161028393929190614abe565b60405180910390f35b61029f61029a366004613b30565b610666565b604051610283929190614ca6565b6102c06102bb366004613b30565b610688565b604051610283919061499b565b6102e06102db36600461406c565b6106b0565b005b6102f56102f0366004613a4b565b610734565b60405161028391906148f3565b610315610310366004613a2f565b6107b7565b6040516102839190614b1e565b610315610330366004613b74565b610866565b61034861034336600461406c565b610919565b6040516102839493929190614bb2565b61036b61036636600461406c565b6109b9565b60405161028394939291906149dc565b61038e610389366004614242565b610a4b565b6040516102839190614b9f565b6102c06103a936600461434a565b610afd565b6102c06103bc366004613b30565b610b7e565b6103d46103cf36600461406c565b611474565b6040516102839291906149b9565b6103ea611507565b604051610283919061465f565b6103ea611516565b61041261040d36600461406c565b611525565b604051610283959493929190614a18565b6102c06104313660046142f1565b6115ca565b6102f5610444366004613bf6565b61164b565b61045c610457366004613cc4565b6116c4565b604051610283919061480c565b610315610477366004613bcb565b61177e565b61031561048a366004613a99565b61182e565b6104a261049d36600461406c565b6118e4565b60405161028393929190614ae9565b6102c0611974565b6103ea61197a565b6104d46104cf36600461406c565b611989565b6040516102839493929190614a7b565b6102f56104f2366004613a4b565b611a1b565b6102c0610505366004613b30565b611a89565b61038e610518366004614242565b612365565b61031561052b366004613d9f565b6123c7565b61054361053e36600461406c565b61241c565b60405161028391906149a4565b61056361055e366004613d48565b6124bf565b60405161028393929190614858565b610585610580366004613a4b565b6125f7565b604051610283929190614976565b6105a66105a136600461429a565b612610565b60405161028393929190614c4a565b6103ea612980565b6103ea61298f565b6103ea61299e565b600080600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a856040518263ffffffff1660e01b81526004016106099190614b1e565b60606040518083038186803b15801561062157600080fd5b505af4158015610635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106599190810190613fc2565b9250925092509193909250565b6000806106738484610b7e565b915061067f8484611a89565b90509250929050565b60008060006106978585610666565b915091506106a582826129ad565b925050505b92915050565b6040517f46eb65cb00000000000000000000000000000000000000000000000000000000815273__$d8b635de2bf4a097b4e18b67d0fb68e779$__906346eb65cb90610700908490600401614b1e565b60006040518083038186803b15801561071857600080fd5b505af415801561072c573d6000803e3d6000fd5b505050505b50565b606060008251905080604051908082528060200260200182016040528015610766578160200160208202803883390190505b50915060005b8181146107af576107908585838151811061078357fe5b6020026020010151611a89565b83828151811061079c57fe5b602090810291909101015260010161076c565b505092915050565b6040517f590aa87500000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063590aa8759061080a90859060040161465f565b60006040518083038186803b15801561082257600080fd5b505af4158015610836573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261085e919081019061409f565b90505b919050565b6040517f63eb399200000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__906363eb3992906108bd9087908790879060040161478c565b60006040518083038186803b1580156108d557600080fd5b505af41580156108e9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610911919081019061409f565b949350505050565b60608060608073__$fddee3b26a806429350031cf3481976d2e$__636f83188e866040518263ffffffff1660e01b81526004016109569190614b1e565b60006040518083038186803b15801561096e57600080fd5b505af4158015610982573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa919081019061410d565b93509350935093509193509193565b6000806000606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016109f79190614b1e565b60006040518083038186803b158015610a0f57600080fd5b505af4158015610a23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613e46565b600080546040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91639caa023b91610aad916001600160a01b0316908890889088906004016147be565b60206040518083038186803b158015610ac557600080fd5b505af4158015610ad9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061091191908101906140ee565b600061091184610b796040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612a1a565b600080610b91838263ffffffff612a2e16565b90506001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415610bec576000610bd884601063ffffffff612a6716565b9050610be48186612a9a565b92505061146d565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415610e055760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401610c589190614b1e565b60606040518083038186803b158015610c7057600080fd5b505af4158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca89190810190613fc2565b6040519194509250606091507f6352211e0000000000000000000000000000000000000000000000000000000090610ce490849060240161499b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051610d5f9190614643565b600060405180830381855afa9150503d8060008114610d9a576040519150601f19603f3d011682016040523d82523d6000602084013e610d9f565b606091505b50915091506000828015610db4575081516020145b610dbf576000610dd0565b610dd082600c63ffffffff612a6716565b9050896001600160a01b0316816001600160a01b031614610df2576000610df5565b60015b60ff16975050505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156110a157600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b8152600401610e739190614b1e565b60006040518083038186803b158015610e8b57600080fd5b505af4158015610e9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec79190810190613eb0565b5081519296509094509250905060005b81811461109757828181518110610eea57fe5b602002602001015160001415610eff5761108f565b83516060907efdd58e00000000000000000000000000000000000000000000000000000000908b90879085908110610f3357fe5b6020026020010151604051602401610f4c9291906147f3565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060876001600160a01b031683604051610fc79190614643565b600060405180830381855afa9150503d8060008114611002576040519150601f19603f3d011682016040523d82523d6000602084013e611007565b606091505b5091509150600082801561101c575081516020145b611027576000611038565b61103882600063ffffffff612b9216565b9050600087868151811061104857fe5b6020026020010151828161105857fe5b049050806110745760009b5050505050505050505050506106aa565b8b81108061108057508b155b1561108957809b505b50505050505b600101610ed7565b505050505061146d565b6001600160e01b031981167fc339d10a0000000000000000000000000000000000000000000000000000000014156111d4576040516060907fa85e59e4000000000000000000000000000000000000000000000000000000009061111090869060009081908190602401614b31565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925260045491519092506000916001600160a01b031690611177908490614643565b600060405180830381855afa9150503d80600081146111b2576040519150601f19603f3d011682016040523d82523d6000602084013e6111b7565b606091505b50509050806111c75760006111cb565b6000195b9350505061146d565b6001600160e01b031981167fdc1600f30000000000000000000000000000000000000000000000000000000014156112fd5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016112409190614b1e565b60006040518083038186803b15801561125857600080fd5b505af415801561126c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112949190810190613e46565b5092509250506112a2612b9e565b6001600160a01b0316826001600160a01b03161480156112cf57506005546001600160a01b038281169116145b156112f65760006112e76112e1612bb6565b88612a9a565b90506112f281612bce565b9450505b505061146d565b6001600160e01b031981167f94cfcdd700000000000000000000000000000000000000000000000000000000141561146d5760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b81526004016113699190614b1e565b60006040518083038186803b15801561138157600080fd5b505af4158015611395573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bd9190810190614002565b80519194509250905060005b818114611468578381815181106113dc57fe5b6020026020010151600014156113f157611460565b60006114108985848151811061140357fe5b6020026020010151610b7e565b9050600085838151811061142057fe5b6020026020010151828161143057fe5b049050806114485760009750505050505050506106aa565b87811080611454575087155b1561145d578097505b50505b6001016113c9565b505050505b5092915050565b60008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__638f4ce479846040518263ffffffff1660e01b81526004016114ae9190614b1e565b604080518083038186803b1580156114c557600080fd5b505af41580156114d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114fd9190810190613e0f565b915091505b915091565b6004546001600160a01b031681565b6000546001600160a01b031681565b600080606080606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b81526004016115649190614b1e565b60006040518083038186803b15801561157c57600080fd5b505af4158015611590573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115b89190810190613eb0565b939a9299509097509550909350915050565b6000610911846116466040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612dcc565b6060808251604051908082528060200260200182016040528015611679578160200160208202803883390190505b50905060005b8351811461146d5783818151811061169357fe5b60200260200101516001600160a01b0316318282815181106116b157fe5b602090810291909101015260010161167f565b6000546040517f02cffc4500000000000000000000000000000000000000000000000000000000815260609173__$7a69f714cdde1cb6b62e3c39bc8c94deae$__916302cffc459161172a916001600160a01b039091169088908890889060040161468d565b60006040518083038186803b15801561174257600080fd5b505af4158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109119190810190613c29565b6040517fa6627e9f00000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063a6627e9f906117d390869086906004016147f3565b60006040518083038186803b1580156117eb57600080fd5b505af41580156117ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611827919081019061409f565b9392505050565b6040517fb43cffe100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063b43cffe190611887908890889088908890600401614746565b60006040518083038186803b15801561189f57600080fd5b505af41580156118b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118db919081019061409f565b95945050505050565b600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6856040518263ffffffff1660e01b81526004016119209190614b1e565b60006040518083038186803b15801561193857600080fd5b505af415801561194c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106599190810190614002565b60065481565b6005546001600160a01b031681565b6000806060600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63ca49f47c866040518263ffffffff1660e01b81526004016119c79190614b1e565b60006040518083038186803b1580156119df57600080fd5b505af41580156119f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613f5a565b606060008251905080604051908082528060200260200182016040528015611a4d578160200160208202803883390190505b50915060005b8181146107af57611a6a8585838151811061140357fe5b838281518110611a7657fe5b6020908102919091010152600101611a53565b600080611a9c838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611c075760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b8152600401611b0a9190614b1e565b60006040518083038186803b158015611b2257600080fd5b505af4158015611b36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b5e9190810190614002565b80519194509250905060005b818114611bfc57838181518110611b7d57fe5b602002602001015160001415611b9257611bf4565b6000611ba48985848151811061078357fe5b90506000858381518110611bb457fe5b60200260200101518281611bc457fe5b04905080611bdc5760009750505050505050506106aa565b87811080611be8575087155b15611bf1578097505b50505b600101611b6a565b506106aa9350505050565b6001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415611c68576000611c4c84601063ffffffff612a6716565b600154909150610be490829087906001600160a01b0316612ddb565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415611fb85760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401611cd49190614b1e565b60606040518083038186803b158015611cec57600080fd5b505af4158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d249190810190613fc2565b600254604051929550909350606092507fe985e9c50000000000000000000000000000000000000000000000000000000091611d70918a916001600160a01b0390911690602401614673565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051611deb9190614643565b600060405180830381855afa9150503d8060008114611e26576040519150601f19603f3d011682016040523d82523d6000602084013e611e2b565b606091505b5091509150811580611e3f57508051602014155b80611e5b5750611e5681600063ffffffff612b9216565b600114155b15611fa9576040516060907f081812fc0000000000000000000000000000000000000000000000000000000090611e9690879060240161499b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050856001600160a01b031681604051611f0d9190614643565b600060405180830381855afa9150503d8060008114611f48576040519150601f19603f3d011682016040523d82523d6000602084013e611f4d565b606091505b509093509150828015611f61575081516020145b8015611f9057506002546001600160a01b0316611f8583600c63ffffffff612a6716565b6001600160a01b0316145b611f9b576000611f9e565b60015b60ff16975050611097565b6000199650505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156121df576040517f9eadc83500000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__90639eadc8359061203d908790600401614b1e565b60006040518083038186803b15801561205557600080fd5b505af4158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613eb0565b5050600354604051929450606093507fe985e9c500000000000000000000000000000000000000000000000000000000926120db925089916001600160a01b031690602401614673565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060836001600160a01b0316836040516121569190614643565b600060405180830381855afa9150503d8060008114612191576040519150601f19603f3d011682016040523d82523d6000602084013e612196565b606091505b50915091508180156121a9575080516020145b80156121c557506121c181600063ffffffff612b9216565b6001145b6121d05760006121d4565b6000195b95505050505061146d565b6001600160e01b031981167fc339d10a00000000000000000000000000000000000000000000000000000000141561221b57600019915061146d565b6001600160e01b031981167fdc1600f300000000000000000000000000000000000000000000000000000000141561146d5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016122879190614b1e565b60006040518083038186803b15801561229f57600080fd5b505af41580156122b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122db9190810190613e46565b5092509250506122e9612b9e565b6001600160a01b0316826001600160a01b031614801561231657506005546001600160a01b038281169116145b1561235c57600061233b612328612bb6565b60055489906001600160a01b0316612ddb565b905060001981146123545761234f81612bce565b612358565b6000195b9450505b50505092915050565b600080546040517f8dccde0400000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91638dccde0491610aad916001600160a01b0316908890889088906004016147be565b6040517fd3d862d100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d3d862d1906117d39086908690600401614906565b6040517fd469502800000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d46950289061246f908590600401614b1e565b60206040518083038186803b15801561248757600080fd5b505af415801561249b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085e9190810190613df4565b60608060606000855190508060405190808252806020026020018201604052801561250457816020015b6124f1613467565b8152602001906001900390816124e95790505b50935080604051908082528060200260200182016040528015612531578160200160208202803883390190505b5092508060405190808252806020026020018201604052801561255e578160200160208202803883390190505b50915060005b8181146125ee5761259b87828151811061257a57fe5b602002602001015187838151811061258e57fe5b6020026020010151612610565b87518890859081106125a957fe5b602002602001018785815181106125bc57fe5b602002602001018786815181106125cf57fe5b9315156020948502919091019093019290925291905252600101612564565b50509250925092565b6060806126048484611a1b565b915061067f8484610734565b612618613467565b600080546040517f9d3fa4b900000000000000000000000000000000000000000000000000000000815282916001600160a01b031690639d3fa4b990612662908890600401614c6e565b60606040518083038186803b15801561267a57600080fd5b505afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126b291908101906141fa565b85516000546040517fa12dcc6f00000000000000000000000000000000000000000000000000000000815292955090916001600160a01b039091169063a12dcc6f906127049089908990600401614c81565b60206040518083038186803b15801561271c57600080fd5b505afa158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127549190810190613dd4565b9150600061276187612ee5565b90506000612782886101800151896101400151612f0190919063ffffffff16565b156127b7576127b0826127a68a60c001518b60800151612f2690919063ffffffff16565b8a60a00151612f42565b9050612824565b60c08801516127d3576127b08289608001518a60a00151612f42565b60006127e4848a6101800151610688565b905060006127fb848b608001518c60a00151612f42565b90506000612812838c60c001518d60a00151612f42565b905061281e82826129ad565b93505050505b61284861284287604001518a60a00151612f6490919063ffffffff16565b826129ad565b9450600460005460208a01516040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__92639caa023b926128b3926001600160a01b03909216918e91908c906004016147be565b60206040518083038186803b1580156128cb57600080fd5b505af41580156128df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061290391908101906140ee565b600481111561290e57fe5b1461291a57600061291c565b845b945061292c886101600151612f83565b61293557600094505b60e0880151158015906129535750612951886101a00151612f83565b155b1561295d57600094505b60038651600681111561296c57fe5b1461297657600094505b5050509250925092565b6001546001600160a01b031681565b6002546001600160a01b031681565b6003546001600160a01b031681565b60008183106129bc5781611827565b5090919050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600061182782612a2985613138565b6131b3565b60008160040183511015612a5457612a54612a4f60038551856004016131ed565b61325c565b5001602001516001600160e01b03191690565b60008160140183511015612a8857612a88612a4f60048551856014016131ed565b5001601401516001600160a01b031690565b60405160009081906060906001600160a01b038616907f70a082310000000000000000000000000000000000000000000000000000000090612ae090879060240161465f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612b339190614643565b600060405180830381855afa9150503d8060008114612b6e576040519150601f19603f3d011682016040523d82523d6000602084013e612b73565b606091505b5091509150818015612b86575080516020145b156107af576106a58160005b60006118278383613264565b736b175474e89094c44da98b954eedeac495271d0f90565b7306af07097c9eeb7fd685c692751d5c66db49c21590565b600080612bd9612bb6565b6001600160a01b0316634ba2363a6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c4b91908101906140d2565b90506000816001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cc29190810190614402565b4211612d4057816001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d0357600080fd5b505af1158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3b9190810190614402565b612db3565b816001600160a01b0316639f678cca6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612db39190810190614402565b9050610911816b033b2e3c9fd0803ce800000086612f42565b600061182782612a298561328e565b60405160009081906060906001600160a01b038716907fdd62ed3e0000000000000000000000000000000000000000000000000000000090612e239088908890602401614673565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612e769190614643565b600060405180830381855afa9150503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5091509150818015612ec9575080516020145b15612edc57612ed9816000612b92565b92505b50509392505050565b6000806000612ef384613347565b9150915061091182826129ad565b6000815183511480156118275750508051602091820120825192909101919091201490565b60008282018381101561182757611827612a4f6000868661338a565b600061091183612f58868563ffffffff6133a916565b9063ffffffff6133da16565b600082821115612f7d57612f7d612a4f6002858561338a565b50900390565b60006020825181612f9057fe5b06600414612fa057506000610861565b6000612fb2838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd70000000000000000000000000000000000000000000000000000000014612fef576001915050610861565b6040517fbbb2dcf600000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063bbb2dcf690613042908790600401614b1e565b60006040518083038186803b15801561305a57600080fd5b505af415801561306e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130969190810190614002565b80519093509150600090505b81811461312c5760006130d260008584815181106130bc57fe5b6020026020010151612a2e90919063ffffffff16565b90506001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415613123576131108483613404565b1561312357600095505050505050610861565b506001016130a2565b50600195945050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc7154150881529485019590955290830191909152948101949094526001600160a01b039091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6060632800659560e01b84848460405160240161320c93929190614b91565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915290509392505050565b805160208201fd5b6000816020018351101561328557613285612a4f60058551856020016131ed565b50016020015190565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534939092909160208710156132da57fe5b601f1987018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b600080600483610140015151101561336457506000905080611502565b6133778360000151846101400151610b7e565b6114fd8460000151856101400151611a89565b606063e946c1bb60e01b84848460405160240161320c93929190614b6f565b6000826133b8575060006106aa565b828202828482816133c557fe5b041461182757611827612a4f6001868661338a565b6000816133f0576133f0612a4f6003858561338a565b60008284816133fb57fe5b04949350505050565b8151600090600183015b818110156107af5761344f85828151811061342557fe5b602002602001015186868151811061343957fe5b6020026020010151612f0190919063ffffffff16565b1561345f576001925050506106aa565b60010161340e565b6040805160608101909152806000815260006020820181905260409091015290565b80356106aa81614d59565b80516106aa81614d59565b600082601f8301126134af578081fd5b81356134c26134bd82614cdb565b614cb4565b8181529150602080830190848101818402860182018710156134e357600080fd5b60005b848110156114685781356134f981614d59565b845292820192908201906001016134e6565b600082601f83011261351b578081fd5b81356135296134bd82614cdb565b8181529150602080830190840160005b838110156135665761355187602084358901016136fa565b83526020928301929190910190600101613539565b5050505092915050565b600082601f830112613580578081fd5b815161358e6134bd82614cdb565b8181529150602080830190840160005b83811015613566576135b68760208451890101613748565b8352602092830192919091019060010161359e565b600082601f8301126135db578081fd5b81356135e96134bd82614cdb565b8181529150602080830190840160005b8381101561356657613611876020843589010161379d565b835260209283019291909101906001016135f9565b600082601f830112613636578081fd5b81356136446134bd82614cdb565b81815291506020808301908481018184028601820187101561366557600080fd5b60005b8481101561146857813584529282019290820190600101613668565b600082601f830112613694578081fd5b81516136a26134bd82614cdb565b8181529150602080830190848101818402860182018710156136c357600080fd5b60005b84811015611468578151845292820192908201906001016136c6565b80516001600160e01b0319811681146106aa57600080fd5b600082601f83011261370a578081fd5b81356137186134bd82614cfb565b915080825283602082850101111561372f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112613758578081fd5b81516137666134bd82614cfb565b915080825283602082850101111561377d57600080fd5b61146d816020840160208601614d1f565b8051600581106106aa57600080fd5b60006101c08083850312156137b0578182fd5b6137b981614cb4565b9150506137c68383613489565b81526137d58360208401613489565b60208201526137e78360408401613489565b60408201526137f98360608401613489565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff8082111561385b57600080fd5b613867868387016136fa565b8385015261016092508285013591508082111561388357600080fd5b61388f868387016136fa565b838501526101809250828501359150808211156138ab57600080fd5b6138b7868387016136fa565b838501526101a09250828501359150808211156138d357600080fd5b506138e0858286016136fa565b82840152505092915050565b60006101c08083850312156138ff578182fd5b61390881614cb4565b9150506139158383613494565b81526139248360208401613494565b60208201526139368360408401613494565b60408201526139488360608401613494565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156139aa57600080fd5b6139b686838701613748565b838501526101609250828501519150808211156139d257600080fd5b6139de86838701613748565b838501526101809250828501519150808211156139fa57600080fd5b613a0686838701613748565b838501526101a0925082850151915080821115613a2257600080fd5b506138e085828601613748565b600060208284031215613a40578081fd5b813561182781614d59565b60008060408385031215613a5d578081fd5b8235613a6881614d59565b9150602083013567ffffffffffffffff811115613a83578182fd5b613a8f8582860161350b565b9150509250929050565b60008060008060808587031215613aae578182fd5b8435613ab981614d59565b9350602085013567ffffffffffffffff80821115613ad5578384fd5b613ae188838901613626565b94506040870135915080821115613af6578384fd5b613b0288838901613626565b93506060870135915080821115613b17578283fd5b50613b24878288016136fa565b91505092959194509250565b60008060408385031215613b42578182fd5b8235613b4d81614d59565b9150602083013567ffffffffffffffff811115613b68578182fd5b613a8f858286016136fa565b600080600060608486031215613b88578081fd5b8335613b9381614d59565b9250602084013567ffffffffffffffff811115613bae578182fd5b613bba868287016136fa565b925050604084013590509250925092565b60008060408385031215613bdd578182fd5b8235613be881614d59565b946020939093013593505050565b600060208284031215613c07578081fd5b813567ffffffffffffffff811115613c1d578182fd5b6109118482850161349f565b60006020808385031215613c3b578182fd5b825167ffffffffffffffff811115613c51578283fd5b80840185601f820112613c62578384fd5b80519150613c726134bd83614cdb565b8281528381019082850185850284018601891015613c8e578687fd5b8693505b84841015613cb857613ca4898261378e565b835260019390930192918501918501613c92565b50979650505050505050565b600080600060608486031215613cd8578081fd5b833567ffffffffffffffff80821115613cef578283fd5b613cfb878388016135cb565b94506020860135915080821115613d10578283fd5b613d1c8783880161349f565b93506040860135915080821115613d31578283fd5b50613d3e86828701613626565b9150509250925092565b60008060408385031215613d5a578182fd5b823567ffffffffffffffff80821115613d71578384fd5b613d7d868387016135cb565b93506020850135915080821115613d92578283fd5b50613a8f8582860161350b565b60008060408385031215613db1578182fd5b823567ffffffffffffffff80821115613dc8578384fd5b613d7d86838701613626565b600060208284031215613de5578081fd5b81518015158114611827578182fd5b600060208284031215613e05578081fd5b61182783836136e2565b60008060408385031215613e21578182fd5b613e2b84846136e2565b91506020830151613e3b81614d59565b809150509250929050565b60008060008060808587031215613e5b578182fd5b8451613e6681614d6e565b6020860151909450613e7781614d59565b6040860151909350613e8881614d59565b606086015190925067ffffffffffffffff811115613ea4578182fd5b613b2487828801613748565b600080600080600060a08688031215613ec7578283fd5b613ed187876136e2565b94506020860151613ee181614d59565b604087015190945067ffffffffffffffff80821115613efe578485fd5b613f0a89838a01613684565b94506060880151915080821115613f1f578283fd5b613f2b89838a01613684565b93506080880151915080821115613f40578283fd5b50613f4d88828901613748565b9150509295509295909350565b60008060008060808587031215613f6f578182fd5b613f7986866136e2565b93506020850151613f8981614d59565b604086015190935067ffffffffffffffff811115613fa5578283fd5b613fb187828801613748565b606096909601519497939650505050565b600080600060608486031215613fd6578081fd5b613fe085856136e2565b92506020840151613ff081614d59565b80925050604084015190509250925092565b600080600060608486031215614016578081fd5b835161402181614d6e565b602085015190935067ffffffffffffffff8082111561403e578283fd5b61404a87838801613684565b9350604086015191508082111561405f578283fd5b50613d3e86828701613570565b60006020828403121561407d578081fd5b813567ffffffffffffffff811115614093578182fd5b610911848285016136fa565b6000602082840312156140b0578081fd5b815167ffffffffffffffff8111156140c6578182fd5b61091184828501613748565b6000602082840312156140e3578081fd5b815161182781614d59565b6000602082840312156140ff578081fd5b815160058110611827578182fd5b60008060008060808587031215614122578182fd5b845167ffffffffffffffff80821115614139578384fd5b61414588838901613748565b955060209150818701518181111561415b578485fd5b80880189601f82011261416c578586fd5b8051915061417c6134bd83614cdb565b82815284810190828601885b858110156141b15761419f8e8984518801016138ec565b84529287019290870190600101614188565b505060408b01519098509450505050808211156141cc578384fd5b6141d888838901613684565b935060608701519150808211156141ed578283fd5b50613b2487828801613570565b60006060828403121561420b578081fd5b6142156060614cb4565b825160078110614223578283fd5b8152602083810151908201526040928301519281019290925250919050565b600080600060608486031215614256578081fd5b833567ffffffffffffffff81111561426c578182fd5b6142788682870161379d565b935050602084013561428981614d59565b929592945050506040919091013590565b600080604083850312156142ac578182fd5b823567ffffffffffffffff808211156142c3578384fd5b6142cf8683870161379d565b935060208501359150808211156142e4578283fd5b50613a8f858286016136fa565b600080600060608486031215614305578081fd5b833567ffffffffffffffff81111561431b578182fd5b6143278682870161379d565b93505060208401359150604084013561433f81614d59565b809150509250925092565b60008060006060848603121561435e578081fd5b833567ffffffffffffffff80821115614375578283fd5b81860160a08189031215614387578384fd5b61439160a0614cb4565b92508035835260208101356020840152604081013560408401526143b88860608301613489565b60608401526080810135828111156143ce578485fd5b6143da898284016136fa565b6080850152509194505050602084013591506143f98560408601613489565b90509250925092565b600060208284031215614413578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208401935060208301825b828110156144615781516001600160a01b031686526020958601959091019060010161443a565b5093949350505050565b600081518084526020840180819550602083028101915060208501845b848110156144b65782840388526144a08483516144f3565b6020988901989094509190910190600101614488565b50919695505050505050565b6000815180845260208401935060208301825b828110156144615781518652602095860195909101906001016144d5565b6000815180845261450b816020860160208601614d1f565b601f01601f19169290920160200192915050565b80516007811061452b57fe5b825260208181015190830152604090810151910152565b60006101c061455284845161441a565b6020830151614564602086018261441a565b506040830151614577604086018261441a565b50606083015161458a606086018261441a565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e08501526101008084015181860152506101208084015181860152506101408084015182828701526145e3838701826144f3565b9150506101609150818401518582038387015261460082826144f3565b92505050610180808401518583038287015261461c83826144f3565b9150506101a09150818401518582038387015261463982826144f3565b9695505050505050565b60008251614655818460208701614d1f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6000608082016001600160a01b03871683526080602084015280865180835260a08501915060a060208202860101925060208801845b82811015614712577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608786030184526146fd858351614542565b945060209384019391909101906001016146c3565b5050505082810360408401526147288186614427565b838103606085015261473a81866144c2565b98975050505050505050565b60006001600160a01b03861682526080602083015261476860808301866144c2565b828103604084015261477a81866144c2565b838103606085015261473a81866144f3565b60006001600160a01b0385168252606060208301526147ae60608301856144f3565b9050826040830152949350505050565b60006001600160a01b038087168352608060208401526147e16080840187614542565b94166040830152506060015292915050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000918401906040840190835b8181101561484d57835161483981614d4f565b835260209384019390920191600101614826565b509095945050505050565b606080825284519082018190526000906020906080840190828801845b8281101561489b5761488884835161451f565b6060939093019290840190600101614875565b505050838103828501526148af81876144c2565b84810360408601528551808252908301915082860190845b818110156148e55782511515845292840192918401916001016148c7565b509198975050505050505050565b60006020825261182760208301846144c2565b60006040825261491960408301856144c2565b602083820381850152818551808452828401915082838202850101838801865b8381101561496757601f198784030185526149558383516144f3565b94860194925090850190600101614939565b50909998505050505050505050565b60006040825261498960408301856144c2565b82810360208401526118db81856144c2565b90815260200190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b60006001600160e01b0319861682526001600160a01b0380861660208401528085166040840152506080606083015261463960808301846144f3565b60006001600160e01b0319871682526001600160a01b038616602083015260a06040830152614a4a60a08301866144c2565b8281036060840152614a5c81866144c2565b8381036080850152614a6e81866144f3565b9998505050505050505050565b60006001600160e01b0319861682526001600160a01b038516602083015260806040830152614aad60808301856144f3565b905082606083015295945050505050565b6001600160e01b03199390931683526001600160a01b03919091166020830152604082015260600190565b60006001600160e01b03198516825260606020830152614b0c60608301856144c2565b8281036040840152614639818561446b565b60006020825261182760208301846144f3565b600060808252614b4460808301876144f3565b6001600160a01b03958616602084015293909416604082015260ff9190911660609091015292915050565b6060810160048510614b7d57fe5b938152602081019290925260409091015290565b6060810160088510614b7d57fe5b60208101614bac83614d4f565b91905290565b600060808252614bc560808301876144f3565b602083820381850152818751808452828401915082838202850101838a01865b83811015614c1357601f19878403018552614c01838351614542565b94860194925090850190600101614be5565b50508681036040880152614c27818a6144c2565b9450505050508281036060840152614c3f818561446b565b979650505050505050565b60a08101614c58828661451f565b8360608301528215156080830152949350505050565b6000602082526118276020830184614542565b600060408252614c946040830185614542565b82810360208401526118db81856144f3565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715614cd357600080fd5b604052919050565b600067ffffffffffffffff821115614cf1578081fd5b5060209081020190565b600067ffffffffffffffff821115614d11578081fd5b50601f01601f191660200190565b60005b83811015614d3a578181015183820152602001614d22565b83811115614d49576000848401525b50505050565b6005811061073157fe5b6001600160a01b038116811461073157600080fd5b6001600160e01b03198116811461073157600080fdfea365627a7a72315820d5f953a2f0be372b5155353406d20980ed27dc327f638f1b56f5c24fc55036106c6578706572696d656e74616cf564736f6c63430005100040" } } }, diff --git a/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json b/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json index ae313e793a..b97789a71d 100644 --- a/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json +++ b/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json @@ -3,6 +3,15 @@ "contractName": "IERC20BridgeSampler", "compilerOutput": { "abi": [ + { + "constant": true, + "inputs": [{ "internalType": "bytes[]", "name": "callDatas", "type": "bytes[]" }], + "name": "batchCall", + "outputs": [{ "internalType": "bytes[]", "name": "callResults", "type": "bytes[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ @@ -74,177 +83,25 @@ { "constant": true, "inputs": [ - { - "components": [ - { "internalType": "address", "name": "makerAddress", "type": "address" }, - { "internalType": "address", "name": "takerAddress", "type": "address" }, - { "internalType": "address", "name": "feeRecipientAddress", "type": "address" }, - { "internalType": "address", "name": "senderAddress", "type": "address" }, - { "internalType": "uint256", "name": "makerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "takerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "makerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "takerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "expirationTimeSeconds", "type": "uint256" }, - { "internalType": "uint256", "name": "salt", "type": "uint256" }, - { "internalType": "bytes", "name": "makerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "makerFeeAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerFeeAssetData", "type": "bytes" } - ], - "internalType": "struct LibOrder.Order[][]", - "name": "orders", - "type": "tuple[][]" - }, - { "internalType": "bytes[][]", "name": "orderSignatures", "type": "bytes[][]" }, - { "internalType": "address[]", "name": "sources", "type": "address[]" }, - { "internalType": "uint256[][]", "name": "makerTokenAmounts", "type": "uint256[][]" } - ], - "name": "queryBatchOrdersAndSampleBuys", - "outputs": [ - { - "components": [ - { "internalType": "uint256[]", "name": "orderFillableAssetAmounts", "type": "uint256[]" }, - { "internalType": "uint256[][]", "name": "tokenAmountsBySource", "type": "uint256[][]" } - ], - "internalType": "struct IERC20BridgeSampler.OrdersAndSample[]", - "name": "ordersAndSamples", - "type": "tuple[]" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "components": [ - { "internalType": "address", "name": "makerAddress", "type": "address" }, - { "internalType": "address", "name": "takerAddress", "type": "address" }, - { "internalType": "address", "name": "feeRecipientAddress", "type": "address" }, - { "internalType": "address", "name": "senderAddress", "type": "address" }, - { "internalType": "uint256", "name": "makerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "takerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "makerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "takerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "expirationTimeSeconds", "type": "uint256" }, - { "internalType": "uint256", "name": "salt", "type": "uint256" }, - { "internalType": "bytes", "name": "makerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "makerFeeAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerFeeAssetData", "type": "bytes" } - ], - "internalType": "struct LibOrder.Order[][]", - "name": "orders", - "type": "tuple[][]" - }, - { "internalType": "bytes[][]", "name": "orderSignatures", "type": "bytes[][]" }, - { "internalType": "address[]", "name": "sources", "type": "address[]" }, - { "internalType": "uint256[][]", "name": "takerTokenAmounts", "type": "uint256[][]" } - ], - "name": "queryBatchOrdersAndSampleSells", - "outputs": [ - { - "components": [ - { "internalType": "uint256[]", "name": "orderFillableAssetAmounts", "type": "uint256[]" }, - { "internalType": "uint256[][]", "name": "tokenAmountsBySource", "type": "uint256[][]" } - ], - "internalType": "struct IERC20BridgeSampler.OrdersAndSample[]", - "name": "ordersAndSamples", - "type": "tuple[]" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "components": [ - { "internalType": "address", "name": "makerAddress", "type": "address" }, - { "internalType": "address", "name": "takerAddress", "type": "address" }, - { "internalType": "address", "name": "feeRecipientAddress", "type": "address" }, - { "internalType": "address", "name": "senderAddress", "type": "address" }, - { "internalType": "uint256", "name": "makerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "takerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "makerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "takerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "expirationTimeSeconds", "type": "uint256" }, - { "internalType": "uint256", "name": "salt", "type": "uint256" }, - { "internalType": "bytes", "name": "makerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "makerFeeAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerFeeAssetData", "type": "bytes" } - ], - "internalType": "struct LibOrder.Order[]", - "name": "orders", - "type": "tuple[]" - }, - { "internalType": "bytes[]", "name": "orderSignatures", "type": "bytes[]" }, - { "internalType": "address[]", "name": "sources", "type": "address[]" }, - { "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" } - ], - "name": "queryOrdersAndSampleBuys", - "outputs": [ - { "internalType": "uint256[]", "name": "orderFillableMakerAssetAmounts", "type": "uint256[]" }, - { "internalType": "uint256[][]", "name": "makerTokenAmountsBySource", "type": "uint256[][]" } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "components": [ - { "internalType": "address", "name": "makerAddress", "type": "address" }, - { "internalType": "address", "name": "takerAddress", "type": "address" }, - { "internalType": "address", "name": "feeRecipientAddress", "type": "address" }, - { "internalType": "address", "name": "senderAddress", "type": "address" }, - { "internalType": "uint256", "name": "makerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "takerAssetAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "makerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "takerFee", "type": "uint256" }, - { "internalType": "uint256", "name": "expirationTimeSeconds", "type": "uint256" }, - { "internalType": "uint256", "name": "salt", "type": "uint256" }, - { "internalType": "bytes", "name": "makerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "makerFeeAssetData", "type": "bytes" }, - { "internalType": "bytes", "name": "takerFeeAssetData", "type": "bytes" } - ], - "internalType": "struct LibOrder.Order[]", - "name": "orders", - "type": "tuple[]" - }, - { "internalType": "bytes[]", "name": "orderSignatures", "type": "bytes[]" }, - { "internalType": "address[]", "name": "sources", "type": "address[]" }, - { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } - ], - "name": "queryOrdersAndSampleSells", - "outputs": [ - { "internalType": "uint256[]", "name": "orderFillableTakerAssetAmounts", "type": "uint256[]" }, - { "internalType": "uint256[][]", "name": "makerTokenAmountsBySource", "type": "uint256[][]" } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { "internalType": "address[]", "name": "sources", "type": "address[]" }, { "internalType": "address", "name": "takerToken", "type": "address" }, { "internalType": "address", "name": "makerToken", "type": "address" }, { "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" } ], - "name": "sampleBuys", - "outputs": [ - { "internalType": "uint256[][]", "name": "takerTokenAmountsBySource", "type": "uint256[][]" } - ], + "name": "sampleBuysFromEth2Dai", + "outputs": [{ "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleBuysFromUniswap", + "outputs": [{ "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" }], "payable": false, "stateMutability": "view", "type": "function" @@ -252,15 +109,38 @@ { "constant": true, "inputs": [ - { "internalType": "address[]", "name": "sources", "type": "address[]" }, { "internalType": "address", "name": "takerToken", "type": "address" }, { "internalType": "address", "name": "makerToken", "type": "address" }, { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } ], - "name": "sampleSells", - "outputs": [ - { "internalType": "uint256[][]", "name": "makerTokenAmountsBySource", "type": "uint256[][]" } + "name": "sampleSellsFromEth2Dai", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } ], + "name": "sampleSellsFromKyberNetwork", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleSellsFromUniswap", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], "payable": false, "stateMutability": "view", "type": "function" @@ -268,6 +148,11 @@ ], "devdoc": { "methods": { + "batchCall(bytes[])": { + "details": "Call multiple public functions on this contract in a single transaction.", + "params": { "callDatas": "ABI-encoded call data for each function call." }, + "return": "callResults ABI-encoded results data for each call." + }, "getOrderFillableMakerAssetAmounts((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[])": { "details": "Queries the fillable maker asset amounts of native orders.", "params": { @@ -284,65 +169,50 @@ }, "return": "orderFillableTakerAssetAmounts How much taker asset can be filled by each order in `orders`." }, - "queryBatchOrdersAndSampleBuys((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[][],bytes[][],address[],uint256[][])": { - "details": "Query batches of native orders and sample buy quotes on multiple DEXes at once.", - "params": { - "makerTokenAmounts": "Batches of Maker token sell amount for each sample.", - "orderSignatures": "Batches of Signatures for each respective order in `orders`.", - "orders": "Batches of Native orders to query.", - "sources": "Address of each DEX. Passing in an unsupported DEX will throw." - }, - "return": "ordersAndSamples How much taker asset can be filled by each order in `orders`. Taker amounts sold for each source at each maker token amount. First indexed by source index, then sample index" - }, - "queryBatchOrdersAndSampleSells((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[][],bytes[][],address[],uint256[][])": { - "details": "Query batches of native orders and sample sell quotes on multiple DEXes at once.", - "params": { - "orderSignatures": "Batches of Signatures for each respective order in `orders`.", - "orders": "Batches of Native orders to query.", - "sources": "Address of each DEX. Passing in an unsupported DEX will throw.", - "takerTokenAmounts": "Batches of Taker token sell amount for each sample." - }, - "return": "ordersAndSamples How much taker asset can be filled by each order in `orders`. Maker amounts bought for each source at each taker token amount. First indexed by source index, then sample index." - }, - "queryOrdersAndSampleBuys((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[],address[],uint256[])": { - "details": "Query native orders and sample buy quotes on multiple DEXes at once.", - "params": { - "makerTokenAmounts": "Maker token buy amount for each sample.", - "orderSignatures": "Signatures for each respective order in `orders`.", - "orders": "Native orders to query.", - "sources": "Address of each DEX. Passing in an unsupported DEX will throw." - }, - "return": "orderFillableMakerAssetAmounts How much maker asset can be filled by each order in `orders`.takerTokenAmountsBySource Taker amounts sold for each source at each maker token amount. First indexed by source index, then sample index." - }, - "queryOrdersAndSampleSells((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[],address[],uint256[])": { - "details": "Query native orders and sample sell quotes on multiple DEXes at once.", - "params": { - "orderSignatures": "Signatures for each respective order in `orders`.", - "orders": "Native orders to query.", - "sources": "Address of each DEX. Passing in an unsupported DEX will throw.", - "takerTokenAmounts": "Taker token sell amount for each sample." - }, - "return": "orderFillableTakerAssetAmounts How much taker asset can be filled by each order in `orders`.makerTokenAmountsBySource Maker amounts bought for each source at each taker token amount. First indexed by source index, then sample index." - }, - "sampleBuys(address[],address,address,uint256[])": { - "details": "Query native orders and sample buy quotes on multiple DEXes at once.", + "sampleBuysFromEth2Dai(address,address,uint256[])": { + "details": "Sample buy quotes from Eth2Dai/Oasis.", "params": { "makerToken": "Address of the maker token (what to buy).", - "makerTokenAmounts": "Maker token buy amount for each sample.", - "sources": "Address of each DEX. Passing in an unsupported DEX will throw.", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Maker token sell amount for each sample." + }, + "return": "takerTokenAmounts Taker amounts sold at each maker token amount." + }, + "sampleBuysFromUniswap(address,address,uint256[])": { + "details": "Sample buy quotes from Uniswap.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "makerTokenAmounts": "Maker token sell amount for each sample.", "takerToken": "Address of the taker token (what to sell)." }, - "return": "takerTokenAmountsBySource Taker amounts sold for each source at each maker token amount. First indexed by source index, then sample index." + "return": "takerTokenAmounts Taker amounts sold at each maker token amount." }, - "sampleSells(address[],address,address,uint256[])": { - "details": "Sample sell quotes on multiple DEXes at once.", + "sampleSellsFromEth2Dai(address,address,uint256[])": { + "details": "Sample sell quotes from Eth2Dai/Oasis.", "params": { "makerToken": "Address of the maker token (what to buy).", - "sources": "Address of each DEX. Passing in an unsupported DEX will throw.", "takerToken": "Address of the taker token (what to sell).", "takerTokenAmounts": "Taker token sell amount for each sample." }, - "return": "makerTokenAmountsBySource Maker amounts bought for each source at each taker token amount. First indexed by source index, then sample index." + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + }, + "sampleSellsFromKyberNetwork(address,address,uint256[])": { + "details": "Sample sell quotes from Kyber.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + }, + "sampleSellsFromUniswap(address,address,uint256[])": { + "details": "Sample sell quotes from Uniswap.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." } } }, diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index f3509b19ab..f80c0b218d 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -22,6 +22,10 @@ { "note": "Remove `LibTransactionDecoder`", "pr": 2464 + }, + { + "note": "Update `IERC20BridgeSampler` wrapper", + "pr": 2477 } ], "timestamp": 1581204851 diff --git a/packages/contract-wrappers/src/generated-wrappers/dev_utils.ts b/packages/contract-wrappers/src/generated-wrappers/dev_utils.ts index 78c2c7d07c..6189e787a5 100644 --- a/packages/contract-wrappers/src/generated-wrappers/dev_utils.ts +++ b/packages/contract-wrappers/src/generated-wrappers/dev_utils.ts @@ -42,7 +42,7 @@ export class DevUtilsContract extends BaseContract { * @ignore */ public static deployedBytecode = - '0x608060405234801561001057600080fd5b506004361061025c5760003560e01c8063a5cd62ba11610145578063d3637905116100bd578063e4e6e7da1161008c578063ee18599711610071578063ee185997146105b5578063ef3bb097146105bd578063ff84e7cc146105c55761025c565b8063e4e6e7da14610572578063e77286eb146105935761025c565b8063d36379051461050a578063d3d862d11461051d578063d469502814610530578063e25cabf7146105505761025c565b8063c26cfecd11610114578063ca49f47c116100f9578063ca49f47c146104c1578063d001c5dc146104e4578063d186037f146104f75761025c565b8063c26cfecd146104b1578063c82037ef146104b95761025c565b8063a5cd62ba14610449578063a6627e9f14610469578063b43cffe11461047c578063bbb2dcf61461048f5761025c565b80637982653e116101d85780639baf2705116101a75780639eadc8351161018c5780639eadc835146103ff578063a070cac814610423578063a0901e51146104365761025c565b80639baf2705146103e25780639cd01605146103f75761025c565b80637982653e1461037b57806379c9c4261461039b5780637d727512146103ae5780638f4ce479146103c15761025c565b80634dfdac201161022f57806363eb39921161021457806363eb3992146103225780636f83188e14610335578063750bdb30146103585761025c565b80634dfdac20146102e2578063590aa875146103025761025c565b806304a5618a146102615780630d7b7d761461028c5780632322cf76146102ad57806346eb65cb146102cd575b600080fd5b61027461026f36600461406c565b6105cd565b60405161028393929190614aee565b60405180910390f35b61029f61029a366004613b30565b610666565b604051610283929190614cd6565b6102c06102bb366004613b30565b610688565b60405161028391906149cb565b6102e06102db36600461406c565b6106b0565b005b6102f56102f0366004613a4b565b610734565b6040516102839190614923565b610315610310366004613a2f565b6107b7565b6040516102839190614b4e565b610315610330366004613b74565b610866565b61034861034336600461406c565b610919565b6040516102839493929190614be2565b61036b61036636600461406c565b6109b9565b6040516102839493929190614a0c565b61038e610389366004614242565b610a4b565b6040516102839190614bcf565b6102c06103a936600461434a565b610afd565b6102c06103bc366004613b30565b610b7e565b6103d46103cf36600461406c565b611474565b6040516102839291906149e9565b6103ea611507565b604051610283919061467e565b6103ea611516565b61041261040d36600461406c565b611525565b604051610283959493929190614a48565b6102c06104313660046142f1565b6115ca565b6102f5610444366004613bf6565b61164b565b61045c610457366004613cc4565b6116c4565b604051610283919061482b565b610315610477366004613bcb565b61177e565b61031561048a366004613a99565b61182e565b6104a261049d36600461406c565b6118e4565b60405161028393929190614b19565b6102c0611974565b6103ea61197a565b6104d46104cf36600461406c565b611989565b6040516102839493929190614aab565b6102f56104f2366004613a4b565b611a1b565b6102c0610505366004613b30565b611a89565b61038e610518366004614242565b612365565b61031561052b366004613d9f565b6123c7565b61054361053e36600461406c565b61241c565b60405161028391906149d4565b61056361055e366004613d48565b6124bf565b60405161028393929190614877565b610585610580366004613a4b565b6125f7565b6040516102839291906149a6565b6105a66105a136600461429a565b612610565b60405161028393929190614c7a565b6103ea612980565b6103ea61298f565b6103ea61299e565b600080600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a856040518263ffffffff1660e01b81526004016106099190614b4e565b60606040518083038186803b15801561062157600080fd5b505af4158015610635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106599190810190613fc2565b9250925092509193909250565b6000806106738484610b7e565b915061067f8484611a89565b90509250929050565b60008060006106978585610666565b915091506106a582826129ad565b925050505b92915050565b6040517f46eb65cb00000000000000000000000000000000000000000000000000000000815273__$d8b635de2bf4a097b4e18b67d0fb68e779$__906346eb65cb90610700908490600401614b4e565b60006040518083038186803b15801561071857600080fd5b505af415801561072c573d6000803e3d6000fd5b505050505b50565b606060008251905080604051908082528060200260200182016040528015610766578160200160208202803883390190505b50915060005b8181146107af576107908585838151811061078357fe5b6020026020010151611a89565b83828151811061079c57fe5b602090810291909101015260010161076c565b505092915050565b6040517f590aa87500000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063590aa8759061080a90859060040161467e565b60006040518083038186803b15801561082257600080fd5b505af4158015610836573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261085e919081019061409f565b90505b919050565b6040517f63eb399200000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__906363eb3992906108bd908790879087906004016147ab565b60006040518083038186803b1580156108d557600080fd5b505af41580156108e9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610911919081019061409f565b949350505050565b60608060608073__$fddee3b26a806429350031cf3481976d2e$__636f83188e866040518263ffffffff1660e01b81526004016109569190614b4e565b60006040518083038186803b15801561096e57600080fd5b505af4158015610982573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa919081019061410d565b93509350935093509193509193565b6000806000606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016109f79190614b4e565b60006040518083038186803b158015610a0f57600080fd5b505af4158015610a23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613e46565b600080546040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91639caa023b91610aad916001600160a01b0316908890889088906004016147dd565b60206040518083038186803b158015610ac557600080fd5b505af4158015610ad9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061091191908101906140ee565b600061091184610b796040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612a1a565b600080610b91838263ffffffff612a2e16565b90506001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415610bec576000610bd884601063ffffffff612a6716565b9050610be48186612a9a565b92505061146d565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415610e055760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401610c589190614b4e565b60606040518083038186803b158015610c7057600080fd5b505af4158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca89190810190613fc2565b6040519194509250606091507f6352211e0000000000000000000000000000000000000000000000000000000090610ce49084906024016149cb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051610d5f9190614662565b600060405180830381855afa9150503d8060008114610d9a576040519150601f19603f3d011682016040523d82523d6000602084013e610d9f565b606091505b50915091506000828015610db4575081516020145b610dbf576000610dd0565b610dd082600c63ffffffff612a6716565b9050896001600160a01b0316816001600160a01b031614610df2576000610df5565b60015b60ff16975050505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156110a157600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b8152600401610e739190614b4e565b60006040518083038186803b158015610e8b57600080fd5b505af4158015610e9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec79190810190613eb0565b5081519296509094509250905060005b81811461109757828181518110610eea57fe5b602002602001015160001415610eff5761108f565b83516060907efdd58e00000000000000000000000000000000000000000000000000000000908b90879085908110610f3357fe5b6020026020010151604051602401610f4c929190614812565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060876001600160a01b031683604051610fc79190614662565b600060405180830381855afa9150503d8060008114611002576040519150601f19603f3d011682016040523d82523d6000602084013e611007565b606091505b5091509150600082801561101c575081516020145b611027576000611038565b61103882600063ffffffff612b9216565b9050600087868151811061104857fe5b6020026020010151828161105857fe5b049050806110745760009b5050505050505050505050506106aa565b8b81108061108057508b155b1561108957809b505b50505050505b600101610ed7565b505050505061146d565b6001600160e01b031981167fc339d10a0000000000000000000000000000000000000000000000000000000014156111d4576040516060907fa85e59e4000000000000000000000000000000000000000000000000000000009061111090869060009081908190602401614b61565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925260045491519092506000916001600160a01b031690611177908490614662565b600060405180830381855afa9150503d80600081146111b2576040519150601f19603f3d011682016040523d82523d6000602084013e6111b7565b606091505b50509050806111c75760006111cb565b6000195b9350505061146d565b6001600160e01b031981167fdc1600f30000000000000000000000000000000000000000000000000000000014156112fd5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016112409190614b4e565b60006040518083038186803b15801561125857600080fd5b505af415801561126c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112949190810190613e46565b5092509250506112a2612b9e565b6001600160a01b0316826001600160a01b03161480156112cf57506005546001600160a01b038281169116145b156112f65760006112e76112e1612bb6565b88612a9a565b90506112f281612bce565b9450505b505061146d565b6001600160e01b031981167f94cfcdd700000000000000000000000000000000000000000000000000000000141561146d5760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b81526004016113699190614b4e565b60006040518083038186803b15801561138157600080fd5b505af4158015611395573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bd9190810190614002565b80519194509250905060005b818114611468578381815181106113dc57fe5b6020026020010151600014156113f157611460565b60006114108985848151811061140357fe5b6020026020010151610b7e565b9050600085838151811061142057fe5b6020026020010151828161143057fe5b049050806114485760009750505050505050506106aa565b87811080611454575087155b1561145d578097505b50505b6001016113c9565b505050505b5092915050565b60008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__638f4ce479846040518263ffffffff1660e01b81526004016114ae9190614b4e565b604080518083038186803b1580156114c557600080fd5b505af41580156114d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114fd9190810190613e0f565b915091505b915091565b6004546001600160a01b031681565b6000546001600160a01b031681565b600080606080606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b81526004016115649190614b4e565b60006040518083038186803b15801561157c57600080fd5b505af4158015611590573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115b89190810190613eb0565b939a9299509097509550909350915050565b6000610911846116466040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612dcc565b6060808251604051908082528060200260200182016040528015611679578160200160208202803883390190505b50905060005b8351811461146d5783818151811061169357fe5b60200260200101516001600160a01b0316318282815181106116b157fe5b602090810291909101015260010161167f565b6000546040517f02cffc4500000000000000000000000000000000000000000000000000000000815260609173__$7a69f714cdde1cb6b62e3c39bc8c94deae$__916302cffc459161172a916001600160a01b03909116908890889088906004016146ac565b60006040518083038186803b15801561174257600080fd5b505af4158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109119190810190613c29565b6040517fa6627e9f00000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063a6627e9f906117d39086908690600401614812565b60006040518083038186803b1580156117eb57600080fd5b505af41580156117ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611827919081019061409f565b9392505050565b6040517fb43cffe100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063b43cffe190611887908890889088908890600401614765565b60006040518083038186803b15801561189f57600080fd5b505af41580156118b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118db919081019061409f565b95945050505050565b600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6856040518263ffffffff1660e01b81526004016119209190614b4e565b60006040518083038186803b15801561193857600080fd5b505af415801561194c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106599190810190614002565b60065481565b6005546001600160a01b031681565b6000806060600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63ca49f47c866040518263ffffffff1660e01b81526004016119c79190614b4e565b60006040518083038186803b1580156119df57600080fd5b505af41580156119f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613f5a565b606060008251905080604051908082528060200260200182016040528015611a4d578160200160208202803883390190505b50915060005b8181146107af57611a6a8585838151811061140357fe5b838281518110611a7657fe5b6020908102919091010152600101611a53565b600080611a9c838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611c075760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b8152600401611b0a9190614b4e565b60006040518083038186803b158015611b2257600080fd5b505af4158015611b36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b5e9190810190614002565b80519194509250905060005b818114611bfc57838181518110611b7d57fe5b602002602001015160001415611b9257611bf4565b6000611ba48985848151811061078357fe5b90506000858381518110611bb457fe5b60200260200101518281611bc457fe5b04905080611bdc5760009750505050505050506106aa565b87811080611be8575087155b15611bf1578097505b50505b600101611b6a565b506106aa9350505050565b6001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415611c68576000611c4c84601063ffffffff612a6716565b600154909150610be490829087906001600160a01b0316612ddb565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415611fb85760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401611cd49190614b4e565b60606040518083038186803b158015611cec57600080fd5b505af4158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d249190810190613fc2565b600254604051929550909350606092507fe985e9c50000000000000000000000000000000000000000000000000000000091611d70918a916001600160a01b0390911690602401614692565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051611deb9190614662565b600060405180830381855afa9150503d8060008114611e26576040519150601f19603f3d011682016040523d82523d6000602084013e611e2b565b606091505b5091509150811580611e3f57508051602014155b80611e5b5750611e5681600063ffffffff612b9216565b600114155b15611fa9576040516060907f081812fc0000000000000000000000000000000000000000000000000000000090611e969087906024016149cb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050856001600160a01b031681604051611f0d9190614662565b600060405180830381855afa9150503d8060008114611f48576040519150601f19603f3d011682016040523d82523d6000602084013e611f4d565b606091505b509093509150828015611f61575081516020145b8015611f9057506002546001600160a01b0316611f8583600c63ffffffff612a6716565b6001600160a01b0316145b611f9b576000611f9e565b60015b60ff16975050611097565b6000199650505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156121df576040517f9eadc83500000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__90639eadc8359061203d908790600401614b4e565b60006040518083038186803b15801561205557600080fd5b505af4158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613eb0565b5050600354604051929450606093507fe985e9c500000000000000000000000000000000000000000000000000000000926120db925089916001600160a01b031690602401614692565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060836001600160a01b0316836040516121569190614662565b600060405180830381855afa9150503d8060008114612191576040519150601f19603f3d011682016040523d82523d6000602084013e612196565b606091505b50915091508180156121a9575080516020145b80156121c557506121c181600063ffffffff612b9216565b6001145b6121d05760006121d4565b6000195b95505050505061146d565b6001600160e01b031981167fc339d10a00000000000000000000000000000000000000000000000000000000141561221b57600019915061146d565b6001600160e01b031981167fdc1600f300000000000000000000000000000000000000000000000000000000141561146d5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016122879190614b4e565b60006040518083038186803b15801561229f57600080fd5b505af41580156122b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122db9190810190613e46565b5092509250506122e9612b9e565b6001600160a01b0316826001600160a01b031614801561231657506005546001600160a01b038281169116145b1561235c57600061233b612328612bb6565b60055489906001600160a01b0316612ddb565b905060001981146123545761234f81612bce565b612358565b6000195b9450505b50505092915050565b600080546040517f8dccde0400000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91638dccde0491610aad916001600160a01b0316908890889088906004016147dd565b6040517fd3d862d100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d3d862d1906117d39086908690600401614936565b6040517fd469502800000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d46950289061246f908590600401614b4e565b60206040518083038186803b15801561248757600080fd5b505af415801561249b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085e9190810190613df4565b60608060606000855190508060405190808252806020026020018201604052801561250457816020015b6124f1613467565b8152602001906001900390816124e95790505b50935080604051908082528060200260200182016040528015612531578160200160208202803883390190505b5092508060405190808252806020026020018201604052801561255e578160200160208202803883390190505b50915060005b8181146125ee5761259b87828151811061257a57fe5b602002602001015187838151811061258e57fe5b6020026020010151612610565b87518890859081106125a957fe5b602002602001018785815181106125bc57fe5b602002602001018786815181106125cf57fe5b9315156020948502919091019093019290925291905252600101612564565b50509250925092565b6060806126048484611a1b565b915061067f8484610734565b612618613467565b600080546040517f9d3fa4b900000000000000000000000000000000000000000000000000000000815282916001600160a01b031690639d3fa4b990612662908890600401614c9e565b60606040518083038186803b15801561267a57600080fd5b505afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126b291908101906141fa565b85516000546040517fa12dcc6f00000000000000000000000000000000000000000000000000000000815292955090916001600160a01b039091169063a12dcc6f906127049089908990600401614cb1565b60206040518083038186803b15801561271c57600080fd5b505afa158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127549190810190613dd4565b9150600061276187612ee5565b90506000612782886101800151896101400151612f0190919063ffffffff16565b156127b7576127b0826127a68a60c001518b60800151612f2690919063ffffffff16565b8a60a00151612f42565b9050612824565b60c08801516127d3576127b08289608001518a60a00151612f42565b60006127e4848a6101800151610688565b905060006127fb848b608001518c60a00151612f42565b90506000612812838c60c001518d60a00151612f42565b905061281e82826129ad565b93505050505b61284861284287604001518a60a00151612f6490919063ffffffff16565b826129ad565b9450600460005460208a01516040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__92639caa023b926128b3926001600160a01b03909216918e91908c906004016147dd565b60206040518083038186803b1580156128cb57600080fd5b505af41580156128df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061290391908101906140ee565b600481111561290e57fe5b1461291a57600061291c565b845b945061292c886101600151612f83565b61293557600094505b60e0880151158015906129535750612951886101a00151612f83565b155b1561295d57600094505b60038651600681111561296c57fe5b1461297657600094505b5050509250925092565b6001546001600160a01b031681565b6002546001600160a01b031681565b6003546001600160a01b031681565b60008183106129bc5781611827565b5090919050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600061182782612a2985613138565b6131b3565b60008160040183511015612a5457612a54612a4f60038551856004016131ed565b61325c565b5001602001516001600160e01b03191690565b60008160140183511015612a8857612a88612a4f60048551856014016131ed565b5001601401516001600160a01b031690565b60405160009081906060906001600160a01b038616907f70a082310000000000000000000000000000000000000000000000000000000090612ae090879060240161467e565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612b339190614662565b600060405180830381855afa9150503d8060008114612b6e576040519150601f19603f3d011682016040523d82523d6000602084013e612b73565b606091505b5091509150818015612b86575080516020145b156107af576106a58160005b60006118278383613264565b736b175474e89094c44da98b954eedeac495271d0f90565b7306af07097c9eeb7fd685c692751d5c66db49c21590565b600080612bd9612bb6565b6001600160a01b0316634ba2363a6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c4b91908101906140d2565b90506000816001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cc29190810190614403565b4211612d4057816001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d0357600080fd5b505af1158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3b9190810190614403565b612db3565b816001600160a01b0316639f678cca6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612db39190810190614403565b9050610911816b033b2e3c9fd0803ce800000086612f42565b600061182782612a298561328e565b60405160009081906060906001600160a01b038716907fdd62ed3e0000000000000000000000000000000000000000000000000000000090612e239088908890602401614692565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612e769190614662565b600060405180830381855afa9150503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5091509150818015612ec9575080516020145b15612edc57612ed9816000612b92565b92505b50509392505050565b6000806000612ef384613347565b9150915061091182826129ad565b6000815183511480156118275750508051602091820120825192909101919091201490565b60008282018381101561182757611827612a4f6000868661338a565b600061091183612f58868563ffffffff6133a916565b9063ffffffff6133da16565b600082821115612f7d57612f7d612a4f6002858561338a565b50900390565b60006020825181612f9057fe5b06600414612fa057506000610861565b6000612fb2838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd70000000000000000000000000000000000000000000000000000000014612fef576001915050610861565b6040517fbbb2dcf600000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063bbb2dcf690613042908790600401614b4e565b60006040518083038186803b15801561305a57600080fd5b505af415801561306e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130969190810190614002565b80519093509150600090505b81811461312c5760006130d260008584815181106130bc57fe5b6020026020010151612a2e90919063ffffffff16565b90506001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415613123576131108483613404565b1561312357600095505050505050610861565b506001016130a2565b50600195945050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc7154150881529485019590955290830191909152948101949094526001600160a01b039091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6060632800659560e01b84848460405160240161320c93929190614bc1565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915290509392505050565b805160208201fd5b6000816020018351101561328557613285612a4f60058551856020016131ed565b50016020015190565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534939092909160208710156132da57fe5b601f1987018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b600080600483610140015151101561336457506000905080611502565b6133778360000151846101400151610b7e565b6114fd8460000151856101400151611a89565b606063e946c1bb60e01b84848460405160240161320c93929190614b9f565b6000826133b8575060006106aa565b828202828482816133c557fe5b041461182757611827612a4f6001868661338a565b6000816133f0576133f0612a4f6003858561338a565b60008284816133fb57fe5b04949350505050565b8151600090600183015b818110156107af5761344f85828151811061342557fe5b602002602001015186868151811061343957fe5b6020026020010151612f0190919063ffffffff16565b1561345f576001925050506106aa565b60010161340e565b6040805160608101909152806000815260006020820181905260409091015290565b80356106aa81614d89565b80516106aa81614d89565b600082601f8301126134af578081fd5b81356134c26134bd82614d0b565b614ce4565b8181529150602080830190848101818402860182018710156134e357600080fd5b60005b848110156114685781356134f981614d89565b845292820192908201906001016134e6565b600082601f83011261351b578081fd5b81356135296134bd82614d0b565b8181529150602080830190840160005b838110156135665761355187602084358901016136fa565b83526020928301929190910190600101613539565b5050505092915050565b600082601f830112613580578081fd5b815161358e6134bd82614d0b565b8181529150602080830190840160005b83811015613566576135b68760208451890101613748565b8352602092830192919091019060010161359e565b600082601f8301126135db578081fd5b81356135e96134bd82614d0b565b8181529150602080830190840160005b8381101561356657613611876020843589010161379d565b835260209283019291909101906001016135f9565b600082601f830112613636578081fd5b81356136446134bd82614d0b565b81815291506020808301908481018184028601820187101561366557600080fd5b60005b8481101561146857813584529282019290820190600101613668565b600082601f830112613694578081fd5b81516136a26134bd82614d0b565b8181529150602080830190848101818402860182018710156136c357600080fd5b60005b84811015611468578151845292820192908201906001016136c6565b80516001600160e01b0319811681146106aa57600080fd5b600082601f83011261370a578081fd5b81356137186134bd82614d2b565b915080825283602082850101111561372f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112613758578081fd5b81516137666134bd82614d2b565b915080825283602082850101111561377d57600080fd5b61146d816020840160208601614d4f565b8051600581106106aa57600080fd5b60006101c08083850312156137b0578182fd5b6137b981614ce4565b9150506137c68383613489565b81526137d58360208401613489565b60208201526137e78360408401613489565b60408201526137f98360608401613489565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff8082111561385b57600080fd5b613867868387016136fa565b8385015261016092508285013591508082111561388357600080fd5b61388f868387016136fa565b838501526101809250828501359150808211156138ab57600080fd5b6138b7868387016136fa565b838501526101a09250828501359150808211156138d357600080fd5b506138e0858286016136fa565b82840152505092915050565b60006101c08083850312156138ff578182fd5b61390881614ce4565b9150506139158383613494565b81526139248360208401613494565b60208201526139368360408401613494565b60408201526139488360608401613494565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156139aa57600080fd5b6139b686838701613748565b838501526101609250828501519150808211156139d257600080fd5b6139de86838701613748565b838501526101809250828501519150808211156139fa57600080fd5b613a0686838701613748565b838501526101a0925082850151915080821115613a2257600080fd5b506138e085828601613748565b600060208284031215613a40578081fd5b813561182781614d89565b60008060408385031215613a5d578081fd5b8235613a6881614d89565b9150602083013567ffffffffffffffff811115613a83578182fd5b613a8f8582860161350b565b9150509250929050565b60008060008060808587031215613aae578182fd5b8435613ab981614d89565b9350602085013567ffffffffffffffff80821115613ad5578384fd5b613ae188838901613626565b94506040870135915080821115613af6578384fd5b613b0288838901613626565b93506060870135915080821115613b17578283fd5b50613b24878288016136fa565b91505092959194509250565b60008060408385031215613b42578182fd5b8235613b4d81614d89565b9150602083013567ffffffffffffffff811115613b68578182fd5b613a8f858286016136fa565b600080600060608486031215613b88578081fd5b8335613b9381614d89565b9250602084013567ffffffffffffffff811115613bae578182fd5b613bba868287016136fa565b925050604084013590509250925092565b60008060408385031215613bdd578182fd5b8235613be881614d89565b946020939093013593505050565b600060208284031215613c07578081fd5b813567ffffffffffffffff811115613c1d578182fd5b6109118482850161349f565b60006020808385031215613c3b578182fd5b825167ffffffffffffffff811115613c51578283fd5b80840185601f820112613c62578384fd5b80519150613c726134bd83614d0b565b8281528381019082850185850284018601891015613c8e578687fd5b8693505b84841015613cb857613ca4898261378e565b835260019390930192918501918501613c92565b50979650505050505050565b600080600060608486031215613cd8578081fd5b833567ffffffffffffffff80821115613cef578283fd5b613cfb878388016135cb565b94506020860135915080821115613d10578283fd5b613d1c8783880161349f565b93506040860135915080821115613d31578283fd5b50613d3e86828701613626565b9150509250925092565b60008060408385031215613d5a578182fd5b823567ffffffffffffffff80821115613d71578384fd5b613d7d868387016135cb565b93506020850135915080821115613d92578283fd5b50613a8f8582860161350b565b60008060408385031215613db1578182fd5b823567ffffffffffffffff80821115613dc8578384fd5b613d7d86838701613626565b600060208284031215613de5578081fd5b81518015158114611827578182fd5b600060208284031215613e05578081fd5b61182783836136e2565b60008060408385031215613e21578182fd5b613e2b84846136e2565b91506020830151613e3b81614d89565b809150509250929050565b60008060008060808587031215613e5b578182fd5b8451613e6681614d9e565b6020860151909450613e7781614d89565b6040860151909350613e8881614d89565b606086015190925067ffffffffffffffff811115613ea4578182fd5b613b2487828801613748565b600080600080600060a08688031215613ec7578283fd5b613ed187876136e2565b94506020860151613ee181614d89565b604087015190945067ffffffffffffffff80821115613efe578485fd5b613f0a89838a01613684565b94506060880151915080821115613f1f578283fd5b613f2b89838a01613684565b93506080880151915080821115613f40578283fd5b50613f4d88828901613748565b9150509295509295909350565b60008060008060808587031215613f6f578182fd5b613f7986866136e2565b93506020850151613f8981614d89565b604086015190935067ffffffffffffffff811115613fa5578283fd5b613fb187828801613748565b606096909601519497939650505050565b600080600060608486031215613fd6578081fd5b613fe085856136e2565b92506020840151613ff081614d89565b80925050604084015190509250925092565b600080600060608486031215614016578081fd5b835161402181614d9e565b602085015190935067ffffffffffffffff8082111561403e578283fd5b61404a87838801613684565b9350604086015191508082111561405f578283fd5b50613d3e86828701613570565b60006020828403121561407d578081fd5b813567ffffffffffffffff811115614093578182fd5b610911848285016136fa565b6000602082840312156140b0578081fd5b815167ffffffffffffffff8111156140c6578182fd5b61091184828501613748565b6000602082840312156140e3578081fd5b815161182781614d89565b6000602082840312156140ff578081fd5b815160058110611827578182fd5b60008060008060808587031215614122578182fd5b845167ffffffffffffffff80821115614139578384fd5b61414588838901613748565b955060209150818701518181111561415b578485fd5b80880189601f82011261416c578586fd5b8051915061417c6134bd83614d0b565b82815284810190828601885b858110156141b15761419f8e8984518801016138ec565b84529287019290870190600101614188565b505060408b01519098509450505050808211156141cc578384fd5b6141d888838901613684565b935060608701519150808211156141ed578283fd5b50613b2487828801613570565b60006060828403121561420b578081fd5b6142156060614ce4565b825160078110614223578283fd5b8152602083810151908201526040928301519281019290925250919050565b600080600060608486031215614256578081fd5b833567ffffffffffffffff81111561426c578182fd5b6142788682870161379d565b935050602084013561428981614d89565b929592945050506040919091013590565b600080604083850312156142ac578182fd5b823567ffffffffffffffff808211156142c3578384fd5b6142cf8683870161379d565b935060208501359150808211156142e4578283fd5b50613a8f858286016136fa565b600080600060608486031215614305578081fd5b833567ffffffffffffffff81111561431b578182fd5b6143278682870161379d565b93505060208401359150604084013561433f81614d89565b809150509250925092565b60008060006060848603121561435e578081fd5b833567ffffffffffffffff80821115614375578283fd5b81860160a08189031215614387578384fd5b61439160a0614ce4565b925080358352602081013560208401526040810135604084015260608101356143b981614d89565b60608401526080810135828111156143cf578485fd5b6143db898284016136fa565b6080850152509194505050602084013591506143fa8560408601613489565b90509250925092565b600060208284031215614414578081fd5b5051919050565b1515815260200190565b6000614431838361453e565b505060600190565b6001600160a01b03169052565b6000815180845260208401935060208301825b828110156144805781516001600160a01b0316865260209586019590910190600101614459565b5093949350505050565b600081518084526020840180819550602083028101915060208501845b848110156144d55782840388526144bf848351614512565b60209889019890945091909101906001016144a7565b50919695505050505050565b6000815180845260208401935060208301825b828110156144805781518652602095860195909101906001016144f4565b6000815180845261452a816020860160208601614d4f565b601f01601f19169290920160200192915050565b80516007811061454a57fe5b825260208181015190830152604090810151910152565b60006101c0614571848451614439565b60208301516145836020860182614439565b5060408301516145966040860182614439565b5060608301516145a96060860182614439565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e085015261010080840151818601525061012080840151818601525061014080840151828287015261460283870182614512565b9150506101609150818401518582038387015261461f8282614512565b92505050610180808401518583038287015261463b8382614512565b9150506101a0915081840151858203838701526146588282614512565b9695505050505050565b60008251614674818460208701614d4f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6000608082016001600160a01b03871683526080602084015280865180835260a08501915060a060208202860101925060208801845b82811015614731577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6087860301845261471c858351614561565b945060209384019391909101906001016146e2565b5050505082810360408401526147478186614446565b838103606085015261475981866144e1565b98975050505050505050565b60006001600160a01b03861682526080602083015261478760808301866144e1565b828103604084015261479981866144e1565b83810360608501526147598186614512565b60006001600160a01b0385168252606060208301526147cd6060830185614512565b9050826040830152949350505050565b60006001600160a01b038087168352608060208401526148006080840187614561565b94166040830152506060015292915050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000918401906040840190835b8181101561486c57835161485881614d7f565b835260209384019390920191600101614845565b509095945050505050565b6000606082016060835280865161488e81846149cb565b9150602088019250835b818110156148bc576148ab838551614425565b602094909401939250600101614898565b505083810360208501526148d081876144e1565b91505082810360408401528084516148e881846149cb565b9150602086019250835b818110156149165761490583855161441b565b6020949094019392506001016148f2565b5090979650505050505050565b60006020825261182760208301846144e1565b60006040825261494960408301856144e1565b602083820381850152818551808452828401915082838202850101838801865b8381101561499757601f19878403018552614985838351614512565b94860194925090850190600101614969565b50909998505050505050505050565b6000604082526149b960408301856144e1565b82810360208401526118db81856144e1565b90815260200190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b60006001600160e01b0319861682526001600160a01b038086166020840152808516604084015250608060608301526146586080830184614512565b60006001600160e01b0319871682526001600160a01b038616602083015260a06040830152614a7a60a08301866144e1565b8281036060840152614a8c81866144e1565b8381036080850152614a9e8186614512565b9998505050505050505050565b60006001600160e01b0319861682526001600160a01b038516602083015260806040830152614add6080830185614512565b905082606083015295945050505050565b6001600160e01b03199390931683526001600160a01b03919091166020830152604082015260600190565b60006001600160e01b03198516825260606020830152614b3c60608301856144e1565b8281036040840152614658818561448a565b6000602082526118276020830184614512565b600060808252614b746080830187614512565b6001600160a01b03958616602084015293909416604082015260ff9190911660609091015292915050565b6060810160048510614bad57fe5b938152602081019290925260409091015290565b6060810160088510614bad57fe5b60208101614bdc83614d7f565b91905290565b600060808252614bf56080830187614512565b602083820381850152818751808452828401915082838202850101838a01865b83811015614c4357601f19878403018552614c31838351614561565b94860194925090850190600101614c15565b50508681036040880152614c57818a6144e1565b9450505050508281036060840152614c6f818561448a565b979650505050505050565b60a08101614c88828661453e565b8360608301528215156080830152949350505050565b6000602082526118276020830184614561565b600060408252614cc46040830185614561565b82810360208401526118db8185614512565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715614d0357600080fd5b604052919050565b600067ffffffffffffffff821115614d21578081fd5b5060209081020190565b600067ffffffffffffffff821115614d41578081fd5b50601f01601f191660200190565b60005b83811015614d6a578181015183820152602001614d52565b83811115614d79576000848401525b50505050565b6005811061073157fe5b6001600160a01b038116811461073157600080fd5b6001600160e01b03198116811461073157600080fdfea365627a7a72315820d5f953a2f0be372b5155353406d20980ed27dc327f638f1b56f5c24fc55036106c6578706572696d656e74616cf564736f6c63430005100040'; + '0x608060405234801561001057600080fd5b506004361061025c5760003560e01c8063a5cd62ba11610145578063d3637905116100bd578063e4e6e7da1161008c578063ee18599711610071578063ee185997146105b5578063ef3bb097146105bd578063ff84e7cc146105c55761025c565b8063e4e6e7da14610572578063e77286eb146105935761025c565b8063d36379051461050a578063d3d862d11461051d578063d469502814610530578063e25cabf7146105505761025c565b8063c26cfecd11610114578063ca49f47c116100f9578063ca49f47c146104c1578063d001c5dc146104e4578063d186037f146104f75761025c565b8063c26cfecd146104b1578063c82037ef146104b95761025c565b8063a5cd62ba14610449578063a6627e9f14610469578063b43cffe11461047c578063bbb2dcf61461048f5761025c565b80637982653e116101d85780639baf2705116101a75780639eadc8351161018c5780639eadc835146103ff578063a070cac814610423578063a0901e51146104365761025c565b80639baf2705146103e25780639cd01605146103f75761025c565b80637982653e1461037b57806379c9c4261461039b5780637d727512146103ae5780638f4ce479146103c15761025c565b80634dfdac201161022f57806363eb39921161021457806363eb3992146103225780636f83188e14610335578063750bdb30146103585761025c565b80634dfdac20146102e2578063590aa875146103025761025c565b806304a5618a146102615780630d7b7d761461028c5780632322cf76146102ad57806346eb65cb146102cd575b600080fd5b61027461026f36600461406c565b6105cd565b60405161028393929190614abe565b60405180910390f35b61029f61029a366004613b30565b610666565b604051610283929190614ca6565b6102c06102bb366004613b30565b610688565b604051610283919061499b565b6102e06102db36600461406c565b6106b0565b005b6102f56102f0366004613a4b565b610734565b60405161028391906148f3565b610315610310366004613a2f565b6107b7565b6040516102839190614b1e565b610315610330366004613b74565b610866565b61034861034336600461406c565b610919565b6040516102839493929190614bb2565b61036b61036636600461406c565b6109b9565b60405161028394939291906149dc565b61038e610389366004614242565b610a4b565b6040516102839190614b9f565b6102c06103a936600461434a565b610afd565b6102c06103bc366004613b30565b610b7e565b6103d46103cf36600461406c565b611474565b6040516102839291906149b9565b6103ea611507565b604051610283919061465f565b6103ea611516565b61041261040d36600461406c565b611525565b604051610283959493929190614a18565b6102c06104313660046142f1565b6115ca565b6102f5610444366004613bf6565b61164b565b61045c610457366004613cc4565b6116c4565b604051610283919061480c565b610315610477366004613bcb565b61177e565b61031561048a366004613a99565b61182e565b6104a261049d36600461406c565b6118e4565b60405161028393929190614ae9565b6102c0611974565b6103ea61197a565b6104d46104cf36600461406c565b611989565b6040516102839493929190614a7b565b6102f56104f2366004613a4b565b611a1b565b6102c0610505366004613b30565b611a89565b61038e610518366004614242565b612365565b61031561052b366004613d9f565b6123c7565b61054361053e36600461406c565b61241c565b60405161028391906149a4565b61056361055e366004613d48565b6124bf565b60405161028393929190614858565b610585610580366004613a4b565b6125f7565b604051610283929190614976565b6105a66105a136600461429a565b612610565b60405161028393929190614c4a565b6103ea612980565b6103ea61298f565b6103ea61299e565b600080600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a856040518263ffffffff1660e01b81526004016106099190614b1e565b60606040518083038186803b15801561062157600080fd5b505af4158015610635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106599190810190613fc2565b9250925092509193909250565b6000806106738484610b7e565b915061067f8484611a89565b90509250929050565b60008060006106978585610666565b915091506106a582826129ad565b925050505b92915050565b6040517f46eb65cb00000000000000000000000000000000000000000000000000000000815273__$d8b635de2bf4a097b4e18b67d0fb68e779$__906346eb65cb90610700908490600401614b1e565b60006040518083038186803b15801561071857600080fd5b505af415801561072c573d6000803e3d6000fd5b505050505b50565b606060008251905080604051908082528060200260200182016040528015610766578160200160208202803883390190505b50915060005b8181146107af576107908585838151811061078357fe5b6020026020010151611a89565b83828151811061079c57fe5b602090810291909101015260010161076c565b505092915050565b6040517f590aa87500000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063590aa8759061080a90859060040161465f565b60006040518083038186803b15801561082257600080fd5b505af4158015610836573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261085e919081019061409f565b90505b919050565b6040517f63eb399200000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__906363eb3992906108bd9087908790879060040161478c565b60006040518083038186803b1580156108d557600080fd5b505af41580156108e9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610911919081019061409f565b949350505050565b60608060608073__$fddee3b26a806429350031cf3481976d2e$__636f83188e866040518263ffffffff1660e01b81526004016109569190614b1e565b60006040518083038186803b15801561096e57600080fd5b505af4158015610982573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa919081019061410d565b93509350935093509193509193565b6000806000606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016109f79190614b1e565b60006040518083038186803b158015610a0f57600080fd5b505af4158015610a23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613e46565b600080546040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91639caa023b91610aad916001600160a01b0316908890889088906004016147be565b60206040518083038186803b158015610ac557600080fd5b505af4158015610ad9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061091191908101906140ee565b600061091184610b796040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612a1a565b600080610b91838263ffffffff612a2e16565b90506001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415610bec576000610bd884601063ffffffff612a6716565b9050610be48186612a9a565b92505061146d565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415610e055760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401610c589190614b1e565b60606040518083038186803b158015610c7057600080fd5b505af4158015610c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca89190810190613fc2565b6040519194509250606091507f6352211e0000000000000000000000000000000000000000000000000000000090610ce490849060240161499b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051610d5f9190614643565b600060405180830381855afa9150503d8060008114610d9a576040519150601f19603f3d011682016040523d82523d6000602084013e610d9f565b606091505b50915091506000828015610db4575081516020145b610dbf576000610dd0565b610dd082600c63ffffffff612a6716565b9050896001600160a01b0316816001600160a01b031614610df2576000610df5565b60015b60ff16975050505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156110a157600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b8152600401610e739190614b1e565b60006040518083038186803b158015610e8b57600080fd5b505af4158015610e9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec79190810190613eb0565b5081519296509094509250905060005b81811461109757828181518110610eea57fe5b602002602001015160001415610eff5761108f565b83516060907efdd58e00000000000000000000000000000000000000000000000000000000908b90879085908110610f3357fe5b6020026020010151604051602401610f4c9291906147f3565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060876001600160a01b031683604051610fc79190614643565b600060405180830381855afa9150503d8060008114611002576040519150601f19603f3d011682016040523d82523d6000602084013e611007565b606091505b5091509150600082801561101c575081516020145b611027576000611038565b61103882600063ffffffff612b9216565b9050600087868151811061104857fe5b6020026020010151828161105857fe5b049050806110745760009b5050505050505050505050506106aa565b8b81108061108057508b155b1561108957809b505b50505050505b600101610ed7565b505050505061146d565b6001600160e01b031981167fc339d10a0000000000000000000000000000000000000000000000000000000014156111d4576040516060907fa85e59e4000000000000000000000000000000000000000000000000000000009061111090869060009081908190602401614b31565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925260045491519092506000916001600160a01b031690611177908490614643565b600060405180830381855afa9150503d80600081146111b2576040519150601f19603f3d011682016040523d82523d6000602084013e6111b7565b606091505b50509050806111c75760006111cb565b6000195b9350505061146d565b6001600160e01b031981167fdc1600f30000000000000000000000000000000000000000000000000000000014156112fd5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016112409190614b1e565b60006040518083038186803b15801561125857600080fd5b505af415801561126c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112949190810190613e46565b5092509250506112a2612b9e565b6001600160a01b0316826001600160a01b03161480156112cf57506005546001600160a01b038281169116145b156112f65760006112e76112e1612bb6565b88612a9a565b90506112f281612bce565b9450505b505061146d565b6001600160e01b031981167f94cfcdd700000000000000000000000000000000000000000000000000000000141561146d5760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b81526004016113699190614b1e565b60006040518083038186803b15801561138157600080fd5b505af4158015611395573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bd9190810190614002565b80519194509250905060005b818114611468578381815181106113dc57fe5b6020026020010151600014156113f157611460565b60006114108985848151811061140357fe5b6020026020010151610b7e565b9050600085838151811061142057fe5b6020026020010151828161143057fe5b049050806114485760009750505050505050506106aa565b87811080611454575087155b1561145d578097505b50505b6001016113c9565b505050505b5092915050565b60008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__638f4ce479846040518263ffffffff1660e01b81526004016114ae9190614b1e565b604080518083038186803b1580156114c557600080fd5b505af41580156114d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114fd9190810190613e0f565b915091505b915091565b6004546001600160a01b031681565b6000546001600160a01b031681565b600080606080606073__$d8b635de2bf4a097b4e18b67d0fb68e779$__639eadc835876040518263ffffffff1660e01b81526004016115649190614b1e565b60006040518083038186803b15801561157c57600080fd5b505af4158015611590573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115b89190810190613eb0565b939a9299509097509550909350915050565b6000610911846116466040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e3000000000000000000000000000000000000000000000000000000081525087876129c3565b612dcc565b6060808251604051908082528060200260200182016040528015611679578160200160208202803883390190505b50905060005b8351811461146d5783818151811061169357fe5b60200260200101516001600160a01b0316318282815181106116b157fe5b602090810291909101015260010161167f565b6000546040517f02cffc4500000000000000000000000000000000000000000000000000000000815260609173__$7a69f714cdde1cb6b62e3c39bc8c94deae$__916302cffc459161172a916001600160a01b039091169088908890889060040161468d565b60006040518083038186803b15801561174257600080fd5b505af4158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109119190810190613c29565b6040517fa6627e9f00000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063a6627e9f906117d390869086906004016147f3565b60006040518083038186803b1580156117eb57600080fd5b505af41580156117ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611827919081019061409f565b9392505050565b6040517fb43cffe100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063b43cffe190611887908890889088908890600401614746565b60006040518083038186803b15801561189f57600080fd5b505af41580156118b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118db919081019061409f565b95945050505050565b600060608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6856040518263ffffffff1660e01b81526004016119209190614b1e565b60006040518083038186803b15801561193857600080fd5b505af415801561194c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106599190810190614002565b60065481565b6005546001600160a01b031681565b6000806060600073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63ca49f47c866040518263ffffffff1660e01b81526004016119c79190614b1e565b60006040518083038186803b1580156119df57600080fd5b505af41580156119f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109aa9190810190613f5a565b606060008251905080604051908082528060200260200182016040528015611a4d578160200160208202803883390190505b50915060005b8181146107af57611a6a8585838151811061140357fe5b838281518110611a7657fe5b6020908102919091010152600101611a53565b600080611a9c838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611c075760608073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63bbb2dcf6866040518263ffffffff1660e01b8152600401611b0a9190614b1e565b60006040518083038186803b158015611b2257600080fd5b505af4158015611b36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b5e9190810190614002565b80519194509250905060005b818114611bfc57838181518110611b7d57fe5b602002602001015160001415611b9257611bf4565b6000611ba48985848151811061078357fe5b90506000858381518110611bb457fe5b60200260200101518281611bc457fe5b04905080611bdc5760009750505050505050506106aa565b87811080611be8575087155b15611bf1578097505b50505b600101611b6a565b506106aa9350505050565b6001600160e01b031981167ff47261b0000000000000000000000000000000000000000000000000000000001415611c68576000611c4c84601063ffffffff612a6716565b600154909150610be490829087906001600160a01b0316612ddb565b6001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415611fb85760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__6304a5618a866040518263ffffffff1660e01b8152600401611cd49190614b1e565b60606040518083038186803b158015611cec57600080fd5b505af4158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d249190810190613fc2565b600254604051929550909350606092507fe985e9c50000000000000000000000000000000000000000000000000000000091611d70918a916001600160a01b0390911690602401614673565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060846001600160a01b031683604051611deb9190614643565b600060405180830381855afa9150503d8060008114611e26576040519150601f19603f3d011682016040523d82523d6000602084013e611e2b565b606091505b5091509150811580611e3f57508051602014155b80611e5b5750611e5681600063ffffffff612b9216565b600114155b15611fa9576040516060907f081812fc0000000000000000000000000000000000000000000000000000000090611e9690879060240161499b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050856001600160a01b031681604051611f0d9190614643565b600060405180830381855afa9150503d8060008114611f48576040519150601f19603f3d011682016040523d82523d6000602084013e611f4d565b606091505b509093509150828015611f61575081516020145b8015611f9057506002546001600160a01b0316611f8583600c63ffffffff612a6716565b6001600160a01b0316145b611f9b576000611f9e565b60015b60ff16975050611097565b6000199650505050505061146d565b6001600160e01b031981167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156121df576040517f9eadc83500000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__90639eadc8359061203d908790600401614b1e565b60006040518083038186803b15801561205557600080fd5b505af4158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613eb0565b5050600354604051929450606093507fe985e9c500000000000000000000000000000000000000000000000000000000926120db925089916001600160a01b031690602401614673565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006060836001600160a01b0316836040516121569190614643565b600060405180830381855afa9150503d8060008114612191576040519150601f19603f3d011682016040523d82523d6000602084013e612196565b606091505b50915091508180156121a9575080516020145b80156121c557506121c181600063ffffffff612b9216565b6001145b6121d05760006121d4565b6000195b95505050505061146d565b6001600160e01b031981167fc339d10a00000000000000000000000000000000000000000000000000000000141561221b57600019915061146d565b6001600160e01b031981167fdc1600f300000000000000000000000000000000000000000000000000000000141561146d5760008073__$d8b635de2bf4a097b4e18b67d0fb68e779$__63750bdb30866040518263ffffffff1660e01b81526004016122879190614b1e565b60006040518083038186803b15801561229f57600080fd5b505af41580156122b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122db9190810190613e46565b5092509250506122e9612b9e565b6001600160a01b0316826001600160a01b031614801561231657506005546001600160a01b038281169116145b1561235c57600061233b612328612bb6565b60055489906001600160a01b0316612ddb565b905060001981146123545761234f81612bce565b612358565b6000195b9450505b50505092915050565b600080546040517f8dccde0400000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__91638dccde0491610aad916001600160a01b0316908890889088906004016147be565b6040517fd3d862d100000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d3d862d1906117d39086908690600401614906565b6040517fd469502800000000000000000000000000000000000000000000000000000000815260009073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063d46950289061246f908590600401614b1e565b60206040518083038186803b15801561248757600080fd5b505af415801561249b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085e9190810190613df4565b60608060606000855190508060405190808252806020026020018201604052801561250457816020015b6124f1613467565b8152602001906001900390816124e95790505b50935080604051908082528060200260200182016040528015612531578160200160208202803883390190505b5092508060405190808252806020026020018201604052801561255e578160200160208202803883390190505b50915060005b8181146125ee5761259b87828151811061257a57fe5b602002602001015187838151811061258e57fe5b6020026020010151612610565b87518890859081106125a957fe5b602002602001018785815181106125bc57fe5b602002602001018786815181106125cf57fe5b9315156020948502919091019093019290925291905252600101612564565b50509250925092565b6060806126048484611a1b565b915061067f8484610734565b612618613467565b600080546040517f9d3fa4b900000000000000000000000000000000000000000000000000000000815282916001600160a01b031690639d3fa4b990612662908890600401614c6e565b60606040518083038186803b15801561267a57600080fd5b505afa15801561268e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126b291908101906141fa565b85516000546040517fa12dcc6f00000000000000000000000000000000000000000000000000000000815292955090916001600160a01b039091169063a12dcc6f906127049089908990600401614c81565b60206040518083038186803b15801561271c57600080fd5b505afa158015612730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127549190810190613dd4565b9150600061276187612ee5565b90506000612782886101800151896101400151612f0190919063ffffffff16565b156127b7576127b0826127a68a60c001518b60800151612f2690919063ffffffff16565b8a60a00151612f42565b9050612824565b60c08801516127d3576127b08289608001518a60a00151612f42565b60006127e4848a6101800151610688565b905060006127fb848b608001518c60a00151612f42565b90506000612812838c60c001518d60a00151612f42565b905061281e82826129ad565b93505050505b61284861284287604001518a60a00151612f6490919063ffffffff16565b826129ad565b9450600460005460208a01516040517f9caa023b00000000000000000000000000000000000000000000000000000000815273__$7a69f714cdde1cb6b62e3c39bc8c94deae$__92639caa023b926128b3926001600160a01b03909216918e91908c906004016147be565b60206040518083038186803b1580156128cb57600080fd5b505af41580156128df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061290391908101906140ee565b600481111561290e57fe5b1461291a57600061291c565b845b945061292c886101600151612f83565b61293557600094505b60e0880151158015906129535750612951886101a00151612f83565b155b1561295d57600094505b60038651600681111561296c57fe5b1461297657600094505b5050509250925092565b6001546001600160a01b031681565b6002546001600160a01b031681565b6003546001600160a01b031681565b60008183106129bc5781611827565b5090919050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b600061182782612a2985613138565b6131b3565b60008160040183511015612a5457612a54612a4f60038551856004016131ed565b61325c565b5001602001516001600160e01b03191690565b60008160140183511015612a8857612a88612a4f60048551856014016131ed565b5001601401516001600160a01b031690565b60405160009081906060906001600160a01b038616907f70a082310000000000000000000000000000000000000000000000000000000090612ae090879060240161465f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612b339190614643565b600060405180830381855afa9150503d8060008114612b6e576040519150601f19603f3d011682016040523d82523d6000602084013e612b73565b606091505b5091509150818015612b86575080516020145b156107af576106a58160005b60006118278383613264565b736b175474e89094c44da98b954eedeac495271d0f90565b7306af07097c9eeb7fd685c692751d5c66db49c21590565b600080612bd9612bb6565b6001600160a01b0316634ba2363a6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c4b91908101906140d2565b90506000816001600160a01b03166320aba08b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612cc29190810190614402565b4211612d4057816001600160a01b031663c92aecc46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d0357600080fd5b505af1158015612d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3b9190810190614402565b612db3565b816001600160a01b0316639f678cca6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612db39190810190614402565b9050610911816b033b2e3c9fd0803ce800000086612f42565b600061182782612a298561328e565b60405160009081906060906001600160a01b038716907fdd62ed3e0000000000000000000000000000000000000000000000000000000090612e239088908890602401614673565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909416939093179092529051612e769190614643565b600060405180830381855afa9150503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5091509150818015612ec9575080516020145b15612edc57612ed9816000612b92565b92505b50509392505050565b6000806000612ef384613347565b9150915061091182826129ad565b6000815183511480156118275750508051602091820120825192909101919091201490565b60008282018381101561182757611827612a4f6000868661338a565b600061091183612f58868563ffffffff6133a916565b9063ffffffff6133da16565b600082821115612f7d57612f7d612a4f6002858561338a565b50900390565b60006020825181612f9057fe5b06600414612fa057506000610861565b6000612fb2838263ffffffff612a2e16565b90506001600160e01b031981167f94cfcdd70000000000000000000000000000000000000000000000000000000014612fef576001915050610861565b6040517fbbb2dcf600000000000000000000000000000000000000000000000000000000815260609073__$d8b635de2bf4a097b4e18b67d0fb68e779$__9063bbb2dcf690613042908790600401614b1e565b60006040518083038186803b15801561305a57600080fd5b505af415801561306e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130969190810190614002565b80519093509150600090505b81811461312c5760006130d260008584815181106130bc57fe5b6020026020010151612a2e90919063ffffffff16565b90506001600160e01b031981167f02571792000000000000000000000000000000000000000000000000000000001415613123576131108483613404565b1561312357600095505050505050610861565b506001016130a2565b50600195945050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc7154150881529485019590955290830191909152948101949094526001600160a01b039091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6060632800659560e01b84848460405160240161320c93929190614b91565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915290509392505050565b805160208201fd5b6000816020018351101561328557613285612a4f60058551856020016131ed565b50016020015190565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534939092909160208710156132da57fe5b601f1987018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b600080600483610140015151101561336457506000905080611502565b6133778360000151846101400151610b7e565b6114fd8460000151856101400151611a89565b606063e946c1bb60e01b84848460405160240161320c93929190614b6f565b6000826133b8575060006106aa565b828202828482816133c557fe5b041461182757611827612a4f6001868661338a565b6000816133f0576133f0612a4f6003858561338a565b60008284816133fb57fe5b04949350505050565b8151600090600183015b818110156107af5761344f85828151811061342557fe5b602002602001015186868151811061343957fe5b6020026020010151612f0190919063ffffffff16565b1561345f576001925050506106aa565b60010161340e565b6040805160608101909152806000815260006020820181905260409091015290565b80356106aa81614d59565b80516106aa81614d59565b600082601f8301126134af578081fd5b81356134c26134bd82614cdb565b614cb4565b8181529150602080830190848101818402860182018710156134e357600080fd5b60005b848110156114685781356134f981614d59565b845292820192908201906001016134e6565b600082601f83011261351b578081fd5b81356135296134bd82614cdb565b8181529150602080830190840160005b838110156135665761355187602084358901016136fa565b83526020928301929190910190600101613539565b5050505092915050565b600082601f830112613580578081fd5b815161358e6134bd82614cdb565b8181529150602080830190840160005b83811015613566576135b68760208451890101613748565b8352602092830192919091019060010161359e565b600082601f8301126135db578081fd5b81356135e96134bd82614cdb565b8181529150602080830190840160005b8381101561356657613611876020843589010161379d565b835260209283019291909101906001016135f9565b600082601f830112613636578081fd5b81356136446134bd82614cdb565b81815291506020808301908481018184028601820187101561366557600080fd5b60005b8481101561146857813584529282019290820190600101613668565b600082601f830112613694578081fd5b81516136a26134bd82614cdb565b8181529150602080830190848101818402860182018710156136c357600080fd5b60005b84811015611468578151845292820192908201906001016136c6565b80516001600160e01b0319811681146106aa57600080fd5b600082601f83011261370a578081fd5b81356137186134bd82614cfb565b915080825283602082850101111561372f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112613758578081fd5b81516137666134bd82614cfb565b915080825283602082850101111561377d57600080fd5b61146d816020840160208601614d1f565b8051600581106106aa57600080fd5b60006101c08083850312156137b0578182fd5b6137b981614cb4565b9150506137c68383613489565b81526137d58360208401613489565b60208201526137e78360408401613489565b60408201526137f98360608401613489565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff8082111561385b57600080fd5b613867868387016136fa565b8385015261016092508285013591508082111561388357600080fd5b61388f868387016136fa565b838501526101809250828501359150808211156138ab57600080fd5b6138b7868387016136fa565b838501526101a09250828501359150808211156138d357600080fd5b506138e0858286016136fa565b82840152505092915050565b60006101c08083850312156138ff578182fd5b61390881614cb4565b9150506139158383613494565b81526139248360208401613494565b60208201526139368360408401613494565b60408201526139488360608401613494565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156139aa57600080fd5b6139b686838701613748565b838501526101609250828501519150808211156139d257600080fd5b6139de86838701613748565b838501526101809250828501519150808211156139fa57600080fd5b613a0686838701613748565b838501526101a0925082850151915080821115613a2257600080fd5b506138e085828601613748565b600060208284031215613a40578081fd5b813561182781614d59565b60008060408385031215613a5d578081fd5b8235613a6881614d59565b9150602083013567ffffffffffffffff811115613a83578182fd5b613a8f8582860161350b565b9150509250929050565b60008060008060808587031215613aae578182fd5b8435613ab981614d59565b9350602085013567ffffffffffffffff80821115613ad5578384fd5b613ae188838901613626565b94506040870135915080821115613af6578384fd5b613b0288838901613626565b93506060870135915080821115613b17578283fd5b50613b24878288016136fa565b91505092959194509250565b60008060408385031215613b42578182fd5b8235613b4d81614d59565b9150602083013567ffffffffffffffff811115613b68578182fd5b613a8f858286016136fa565b600080600060608486031215613b88578081fd5b8335613b9381614d59565b9250602084013567ffffffffffffffff811115613bae578182fd5b613bba868287016136fa565b925050604084013590509250925092565b60008060408385031215613bdd578182fd5b8235613be881614d59565b946020939093013593505050565b600060208284031215613c07578081fd5b813567ffffffffffffffff811115613c1d578182fd5b6109118482850161349f565b60006020808385031215613c3b578182fd5b825167ffffffffffffffff811115613c51578283fd5b80840185601f820112613c62578384fd5b80519150613c726134bd83614cdb565b8281528381019082850185850284018601891015613c8e578687fd5b8693505b84841015613cb857613ca4898261378e565b835260019390930192918501918501613c92565b50979650505050505050565b600080600060608486031215613cd8578081fd5b833567ffffffffffffffff80821115613cef578283fd5b613cfb878388016135cb565b94506020860135915080821115613d10578283fd5b613d1c8783880161349f565b93506040860135915080821115613d31578283fd5b50613d3e86828701613626565b9150509250925092565b60008060408385031215613d5a578182fd5b823567ffffffffffffffff80821115613d71578384fd5b613d7d868387016135cb565b93506020850135915080821115613d92578283fd5b50613a8f8582860161350b565b60008060408385031215613db1578182fd5b823567ffffffffffffffff80821115613dc8578384fd5b613d7d86838701613626565b600060208284031215613de5578081fd5b81518015158114611827578182fd5b600060208284031215613e05578081fd5b61182783836136e2565b60008060408385031215613e21578182fd5b613e2b84846136e2565b91506020830151613e3b81614d59565b809150509250929050565b60008060008060808587031215613e5b578182fd5b8451613e6681614d6e565b6020860151909450613e7781614d59565b6040860151909350613e8881614d59565b606086015190925067ffffffffffffffff811115613ea4578182fd5b613b2487828801613748565b600080600080600060a08688031215613ec7578283fd5b613ed187876136e2565b94506020860151613ee181614d59565b604087015190945067ffffffffffffffff80821115613efe578485fd5b613f0a89838a01613684565b94506060880151915080821115613f1f578283fd5b613f2b89838a01613684565b93506080880151915080821115613f40578283fd5b50613f4d88828901613748565b9150509295509295909350565b60008060008060808587031215613f6f578182fd5b613f7986866136e2565b93506020850151613f8981614d59565b604086015190935067ffffffffffffffff811115613fa5578283fd5b613fb187828801613748565b606096909601519497939650505050565b600080600060608486031215613fd6578081fd5b613fe085856136e2565b92506020840151613ff081614d59565b80925050604084015190509250925092565b600080600060608486031215614016578081fd5b835161402181614d6e565b602085015190935067ffffffffffffffff8082111561403e578283fd5b61404a87838801613684565b9350604086015191508082111561405f578283fd5b50613d3e86828701613570565b60006020828403121561407d578081fd5b813567ffffffffffffffff811115614093578182fd5b610911848285016136fa565b6000602082840312156140b0578081fd5b815167ffffffffffffffff8111156140c6578182fd5b61091184828501613748565b6000602082840312156140e3578081fd5b815161182781614d59565b6000602082840312156140ff578081fd5b815160058110611827578182fd5b60008060008060808587031215614122578182fd5b845167ffffffffffffffff80821115614139578384fd5b61414588838901613748565b955060209150818701518181111561415b578485fd5b80880189601f82011261416c578586fd5b8051915061417c6134bd83614cdb565b82815284810190828601885b858110156141b15761419f8e8984518801016138ec565b84529287019290870190600101614188565b505060408b01519098509450505050808211156141cc578384fd5b6141d888838901613684565b935060608701519150808211156141ed578283fd5b50613b2487828801613570565b60006060828403121561420b578081fd5b6142156060614cb4565b825160078110614223578283fd5b8152602083810151908201526040928301519281019290925250919050565b600080600060608486031215614256578081fd5b833567ffffffffffffffff81111561426c578182fd5b6142788682870161379d565b935050602084013561428981614d59565b929592945050506040919091013590565b600080604083850312156142ac578182fd5b823567ffffffffffffffff808211156142c3578384fd5b6142cf8683870161379d565b935060208501359150808211156142e4578283fd5b50613a8f858286016136fa565b600080600060608486031215614305578081fd5b833567ffffffffffffffff81111561431b578182fd5b6143278682870161379d565b93505060208401359150604084013561433f81614d59565b809150509250925092565b60008060006060848603121561435e578081fd5b833567ffffffffffffffff80821115614375578283fd5b81860160a08189031215614387578384fd5b61439160a0614cb4565b92508035835260208101356020840152604081013560408401526143b88860608301613489565b60608401526080810135828111156143ce578485fd5b6143da898284016136fa565b6080850152509194505050602084013591506143f98560408601613489565b90509250925092565b600060208284031215614413578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208401935060208301825b828110156144615781516001600160a01b031686526020958601959091019060010161443a565b5093949350505050565b600081518084526020840180819550602083028101915060208501845b848110156144b65782840388526144a08483516144f3565b6020988901989094509190910190600101614488565b50919695505050505050565b6000815180845260208401935060208301825b828110156144615781518652602095860195909101906001016144d5565b6000815180845261450b816020860160208601614d1f565b601f01601f19169290920160200192915050565b80516007811061452b57fe5b825260208181015190830152604090810151910152565b60006101c061455284845161441a565b6020830151614564602086018261441a565b506040830151614577604086018261441a565b50606083015161458a606086018261441a565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e08501526101008084015181860152506101208084015181860152506101408084015182828701526145e3838701826144f3565b9150506101609150818401518582038387015261460082826144f3565b92505050610180808401518583038287015261461c83826144f3565b9150506101a09150818401518582038387015261463982826144f3565b9695505050505050565b60008251614655818460208701614d1f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6000608082016001600160a01b03871683526080602084015280865180835260a08501915060a060208202860101925060208801845b82811015614712577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608786030184526146fd858351614542565b945060209384019391909101906001016146c3565b5050505082810360408401526147288186614427565b838103606085015261473a81866144c2565b98975050505050505050565b60006001600160a01b03861682526080602083015261476860808301866144c2565b828103604084015261477a81866144c2565b838103606085015261473a81866144f3565b60006001600160a01b0385168252606060208301526147ae60608301856144f3565b9050826040830152949350505050565b60006001600160a01b038087168352608060208401526147e16080840187614542565b94166040830152506060015292915050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000918401906040840190835b8181101561484d57835161483981614d4f565b835260209384019390920191600101614826565b509095945050505050565b606080825284519082018190526000906020906080840190828801845b8281101561489b5761488884835161451f565b6060939093019290840190600101614875565b505050838103828501526148af81876144c2565b84810360408601528551808252908301915082860190845b818110156148e55782511515845292840192918401916001016148c7565b509198975050505050505050565b60006020825261182760208301846144c2565b60006040825261491960408301856144c2565b602083820381850152818551808452828401915082838202850101838801865b8381101561496757601f198784030185526149558383516144f3565b94860194925090850190600101614939565b50909998505050505050505050565b60006040825261498960408301856144c2565b82810360208401526118db81856144c2565b90815260200190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b60006001600160e01b0319861682526001600160a01b0380861660208401528085166040840152506080606083015261463960808301846144f3565b60006001600160e01b0319871682526001600160a01b038616602083015260a06040830152614a4a60a08301866144c2565b8281036060840152614a5c81866144c2565b8381036080850152614a6e81866144f3565b9998505050505050505050565b60006001600160e01b0319861682526001600160a01b038516602083015260806040830152614aad60808301856144f3565b905082606083015295945050505050565b6001600160e01b03199390931683526001600160a01b03919091166020830152604082015260600190565b60006001600160e01b03198516825260606020830152614b0c60608301856144c2565b8281036040840152614639818561446b565b60006020825261182760208301846144f3565b600060808252614b4460808301876144f3565b6001600160a01b03958616602084015293909416604082015260ff9190911660609091015292915050565b6060810160048510614b7d57fe5b938152602081019290925260409091015290565b6060810160088510614b7d57fe5b60208101614bac83614d4f565b91905290565b600060808252614bc560808301876144f3565b602083820381850152818751808452828401915082838202850101838a01865b83811015614c1357601f19878403018552614c01838351614542565b94860194925090850190600101614be5565b50508681036040880152614c27818a6144c2565b9450505050508281036060840152614c3f818561446b565b979650505050505050565b60a08101614c58828661451f565b8360608301528215156080830152949350505050565b6000602082526118276020830184614542565b600060408252614c946040830185614542565b82810360208401526118db81856144f3565b918252602082015260400190565b60405181810167ffffffffffffffff81118282101715614cd357600080fd5b604052919050565b600067ffffffffffffffff821115614cf1578081fd5b5060209081020190565b600067ffffffffffffffff821115614d11578081fd5b50601f01601f191660200190565b60005b83811015614d3a578181015183820152602001614d22565b83811115614d49576000848401525b50505050565b6005811061073157fe5b6001600160a01b038116811461073157600080fd5b6001600160e01b03198116811461073157600080fdfea365627a7a72315820d5f953a2f0be372b5155353406d20980ed27dc327f638f1b56f5c24fc55036106c6578706572696d656e74616cf564736f6c63430005100040'; public static contractName = 'DevUtils'; private readonly _methodABIIndex: { [name: string]: number } = {}; public static async deployFrom0xArtifactAsync( diff --git a/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts b/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts index d6d7b1085c..25ae1a6f86 100644 --- a/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts +++ b/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts @@ -161,6 +161,25 @@ export class IERC20BridgeSamplerContract extends BaseContract { */ public static ABI(): ContractAbi { const abi = [ + { + constant: true, + inputs: [ + { + name: 'callDatas', + type: 'bytes[]', + }, + ], + name: 'batchCall', + outputs: [ + { + name: 'callResults', + type: 'bytes[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, { constant: true, inputs: [ @@ -327,382 +346,25 @@ export class IERC20BridgeSamplerContract extends BaseContract { constant: true, inputs: [ { - name: 'orders', - type: 'tuple[][]', - components: [ - { - name: 'makerAddress', - type: 'address', - }, - { - name: 'takerAddress', - type: 'address', - }, - { - name: 'feeRecipientAddress', - type: 'address', - }, - { - name: 'senderAddress', - type: 'address', - }, - { - name: 'makerAssetAmount', - type: 'uint256', - }, - { - name: 'takerAssetAmount', - type: 'uint256', - }, - { - name: 'makerFee', - type: 'uint256', - }, - { - name: 'takerFee', - type: 'uint256', - }, - { - name: 'expirationTimeSeconds', - type: 'uint256', - }, - { - name: 'salt', - type: 'uint256', - }, - { - name: 'makerAssetData', - type: 'bytes', - }, - { - name: 'takerAssetData', - type: 'bytes', - }, - { - name: 'makerFeeAssetData', - type: 'bytes', - }, - { - name: 'takerFeeAssetData', - type: 'bytes', - }, - ], + name: 'takerToken', + type: 'address', }, { - name: 'orderSignatures', - type: 'bytes[][]', - }, - { - name: 'sources', - type: 'address[]', - }, - { - name: 'makerTokenAmounts', - type: 'uint256[][]', - }, - ], - name: 'queryBatchOrdersAndSampleBuys', - outputs: [ - { - name: 'ordersAndSamples', - type: 'tuple[]', - components: [ - { - name: 'orderFillableAssetAmounts', - type: 'uint256[]', - }, - { - name: 'tokenAmountsBySource', - type: 'uint256[][]', - }, - ], - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: 'orders', - type: 'tuple[][]', - components: [ - { - name: 'makerAddress', - type: 'address', - }, - { - name: 'takerAddress', - type: 'address', - }, - { - name: 'feeRecipientAddress', - type: 'address', - }, - { - name: 'senderAddress', - type: 'address', - }, - { - name: 'makerAssetAmount', - type: 'uint256', - }, - { - name: 'takerAssetAmount', - type: 'uint256', - }, - { - name: 'makerFee', - type: 'uint256', - }, - { - name: 'takerFee', - type: 'uint256', - }, - { - name: 'expirationTimeSeconds', - type: 'uint256', - }, - { - name: 'salt', - type: 'uint256', - }, - { - name: 'makerAssetData', - type: 'bytes', - }, - { - name: 'takerAssetData', - type: 'bytes', - }, - { - name: 'makerFeeAssetData', - type: 'bytes', - }, - { - name: 'takerFeeAssetData', - type: 'bytes', - }, - ], - }, - { - name: 'orderSignatures', - type: 'bytes[][]', - }, - { - name: 'sources', - type: 'address[]', - }, - { - name: 'takerTokenAmounts', - type: 'uint256[][]', - }, - ], - name: 'queryBatchOrdersAndSampleSells', - outputs: [ - { - name: 'ordersAndSamples', - type: 'tuple[]', - components: [ - { - name: 'orderFillableAssetAmounts', - type: 'uint256[]', - }, - { - name: 'tokenAmountsBySource', - type: 'uint256[][]', - }, - ], - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: 'orders', - type: 'tuple[]', - components: [ - { - name: 'makerAddress', - type: 'address', - }, - { - name: 'takerAddress', - type: 'address', - }, - { - name: 'feeRecipientAddress', - type: 'address', - }, - { - name: 'senderAddress', - type: 'address', - }, - { - name: 'makerAssetAmount', - type: 'uint256', - }, - { - name: 'takerAssetAmount', - type: 'uint256', - }, - { - name: 'makerFee', - type: 'uint256', - }, - { - name: 'takerFee', - type: 'uint256', - }, - { - name: 'expirationTimeSeconds', - type: 'uint256', - }, - { - name: 'salt', - type: 'uint256', - }, - { - name: 'makerAssetData', - type: 'bytes', - }, - { - name: 'takerAssetData', - type: 'bytes', - }, - { - name: 'makerFeeAssetData', - type: 'bytes', - }, - { - name: 'takerFeeAssetData', - type: 'bytes', - }, - ], - }, - { - name: 'orderSignatures', - type: 'bytes[]', - }, - { - name: 'sources', - type: 'address[]', + name: 'makerToken', + type: 'address', }, { name: 'makerTokenAmounts', type: 'uint256[]', }, ], - name: 'queryOrdersAndSampleBuys', + name: 'sampleBuysFromEth2Dai', outputs: [ - { - name: 'orderFillableMakerAssetAmounts', - type: 'uint256[]', - }, - { - name: 'makerTokenAmountsBySource', - type: 'uint256[][]', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: 'orders', - type: 'tuple[]', - components: [ - { - name: 'makerAddress', - type: 'address', - }, - { - name: 'takerAddress', - type: 'address', - }, - { - name: 'feeRecipientAddress', - type: 'address', - }, - { - name: 'senderAddress', - type: 'address', - }, - { - name: 'makerAssetAmount', - type: 'uint256', - }, - { - name: 'takerAssetAmount', - type: 'uint256', - }, - { - name: 'makerFee', - type: 'uint256', - }, - { - name: 'takerFee', - type: 'uint256', - }, - { - name: 'expirationTimeSeconds', - type: 'uint256', - }, - { - name: 'salt', - type: 'uint256', - }, - { - name: 'makerAssetData', - type: 'bytes', - }, - { - name: 'takerAssetData', - type: 'bytes', - }, - { - name: 'makerFeeAssetData', - type: 'bytes', - }, - { - name: 'takerFeeAssetData', - type: 'bytes', - }, - ], - }, - { - name: 'orderSignatures', - type: 'bytes[]', - }, - { - name: 'sources', - type: 'address[]', - }, { name: 'takerTokenAmounts', type: 'uint256[]', }, ], - name: 'queryOrdersAndSampleSells', - outputs: [ - { - name: 'orderFillableTakerAssetAmounts', - type: 'uint256[]', - }, - { - name: 'makerTokenAmountsBySource', - type: 'uint256[][]', - }, - ], payable: false, stateMutability: 'view', type: 'function', @@ -710,10 +372,6 @@ export class IERC20BridgeSamplerContract extends BaseContract { { constant: true, inputs: [ - { - name: 'sources', - type: 'address[]', - }, { name: 'takerToken', type: 'address', @@ -727,11 +385,11 @@ export class IERC20BridgeSamplerContract extends BaseContract { type: 'uint256[]', }, ], - name: 'sampleBuys', + name: 'sampleBuysFromUniswap', outputs: [ { - name: 'takerTokenAmountsBySource', - type: 'uint256[][]', + name: 'takerTokenAmounts', + type: 'uint256[]', }, ], payable: false, @@ -741,10 +399,6 @@ export class IERC20BridgeSamplerContract extends BaseContract { { constant: true, inputs: [ - { - name: 'sources', - type: 'address[]', - }, { name: 'takerToken', type: 'address', @@ -758,11 +412,65 @@ export class IERC20BridgeSamplerContract extends BaseContract { type: 'uint256[]', }, ], - name: 'sampleSells', + name: 'sampleSellsFromEth2Dai', outputs: [ { - name: 'makerTokenAmountsBySource', - type: 'uint256[][]', + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromKyberNetwork', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromUniswap', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', }, ], payable: false, @@ -848,6 +556,32 @@ export class IERC20BridgeSamplerContract extends BaseContract { return abiEncoder.getSelector(); } + /** + * Call multiple public functions on this contract in a single transaction. + * @param callDatas ABI-encoded call data for each function call. + * @returns callResults ABI-encoded results data for each call. + */ + public batchCall(callDatas: string[]): ContractFunctionObj { + const self = (this as any) as IERC20BridgeSamplerContract; + assert.isArray('callDatas', callDatas); + const functionSignature = 'batchCall(bytes[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [callDatas]); + }, + }; + } /** * Queries the fillable maker asset amounts of native orders. * @param orders Native orders to query. @@ -943,283 +677,24 @@ export class IERC20BridgeSamplerContract extends BaseContract { }; } /** - * Query batches of native orders and sample buy quotes on multiple DEXes at once. - * @param orders Batches of Native orders to query. - * @param orderSignatures Batches of Signatures for each respective order in - * `orders`. - * @param sources Address of each DEX. Passing in an unsupported DEX will - * throw. - * @param makerTokenAmounts Batches of Maker token sell amount for each sample. - * @returns ordersAndSamples How much taker asset can be filled by each order in `orders`. Taker amounts sold for each source at each maker token amount. First indexed by source index, then sample index - */ - public queryBatchOrdersAndSampleBuys( - orders: Array<{ - makerAddress: string; - takerAddress: string; - feeRecipientAddress: string; - senderAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - expirationTimeSeconds: BigNumber; - salt: BigNumber; - makerAssetData: string; - takerAssetData: string; - makerFeeAssetData: string; - takerFeeAssetData: string; - }>[], - orderSignatures: string[][], - sources: string[], - makerTokenAmounts: BigNumber[][], - ): ContractFunctionObj> { - const self = (this as any) as IERC20BridgeSamplerContract; - assert.isArray('orders', orders); - assert.isArray('orderSignatures', orderSignatures); - assert.isArray('sources', sources); - assert.isArray('makerTokenAmounts', makerTokenAmounts); - const functionSignature = - 'queryBatchOrdersAndSampleBuys((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[][],bytes[][],address[],uint256[][])'; - - return { - async callAsync( - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise> { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { ...callData, data: this.getABIEncodedTransactionData() }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue< - Array<{ orderFillableAssetAmounts: BigNumber[]; tokenAmountsBySource: BigNumber[][] }> - >(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - orders, - orderSignatures, - sources, - makerTokenAmounts, - ]); - }, - }; - } - /** - * Query batches of native orders and sample sell quotes on multiple DEXes at once. - * @param orders Batches of Native orders to query. - * @param orderSignatures Batches of Signatures for each respective order in - * `orders`. - * @param sources Address of each DEX. Passing in an unsupported DEX will - * throw. - * @param takerTokenAmounts Batches of Taker token sell amount for each sample. - * @returns ordersAndSamples How much taker asset can be filled by each order in `orders`. Maker amounts bought for each source at each taker token amount. First indexed by source index, then sample index. - */ - public queryBatchOrdersAndSampleSells( - orders: Array<{ - makerAddress: string; - takerAddress: string; - feeRecipientAddress: string; - senderAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - expirationTimeSeconds: BigNumber; - salt: BigNumber; - makerAssetData: string; - takerAssetData: string; - makerFeeAssetData: string; - takerFeeAssetData: string; - }>[], - orderSignatures: string[][], - sources: string[], - takerTokenAmounts: BigNumber[][], - ): ContractFunctionObj> { - const self = (this as any) as IERC20BridgeSamplerContract; - assert.isArray('orders', orders); - assert.isArray('orderSignatures', orderSignatures); - assert.isArray('sources', sources); - assert.isArray('takerTokenAmounts', takerTokenAmounts); - const functionSignature = - 'queryBatchOrdersAndSampleSells((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[][],bytes[][],address[],uint256[][])'; - - return { - async callAsync( - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise> { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { ...callData, data: this.getABIEncodedTransactionData() }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue< - Array<{ orderFillableAssetAmounts: BigNumber[]; tokenAmountsBySource: BigNumber[][] }> - >(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - orders, - orderSignatures, - sources, - takerTokenAmounts, - ]); - }, - }; - } - /** - * Query native orders and sample buy quotes on multiple DEXes at once. - * @param orders Native orders to query. - * @param orderSignatures Signatures for each respective order in `orders`. - * @param sources Address of each DEX. Passing in an unsupported DEX will - * throw. - * @param makerTokenAmounts Maker token buy amount for each sample. - * @returns orderFillableMakerAssetAmounts How much maker asset can be filled by each order in `orders`.takerTokenAmountsBySource Taker amounts sold for each source at each maker token amount. First indexed by source index, then sample index. - */ - public queryOrdersAndSampleBuys( - orders: Array<{ - makerAddress: string; - takerAddress: string; - feeRecipientAddress: string; - senderAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - expirationTimeSeconds: BigNumber; - salt: BigNumber; - makerAssetData: string; - takerAssetData: string; - makerFeeAssetData: string; - takerFeeAssetData: string; - }>, - orderSignatures: string[], - sources: string[], - makerTokenAmounts: BigNumber[], - ): ContractFunctionObj<[BigNumber[], BigNumber[][]]> { - const self = (this as any) as IERC20BridgeSamplerContract; - assert.isArray('orders', orders); - assert.isArray('orderSignatures', orderSignatures); - assert.isArray('sources', sources); - assert.isArray('makerTokenAmounts', makerTokenAmounts); - const functionSignature = - 'queryOrdersAndSampleBuys((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[],address[],uint256[])'; - - return { - async callAsync( - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise<[BigNumber[], BigNumber[][]]> { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { ...callData, data: this.getABIEncodedTransactionData() }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue<[BigNumber[], BigNumber[][]]>(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - orders, - orderSignatures, - sources, - makerTokenAmounts, - ]); - }, - }; - } - /** - * Query native orders and sample sell quotes on multiple DEXes at once. - * @param orders Native orders to query. - * @param orderSignatures Signatures for each respective order in `orders`. - * @param sources Address of each DEX. Passing in an unsupported DEX will - * throw. - * @param takerTokenAmounts Taker token sell amount for each sample. - * @returns orderFillableTakerAssetAmounts How much taker asset can be filled by each order in `orders`.makerTokenAmountsBySource Maker amounts bought for each source at each taker token amount. First indexed by source index, then sample index. - */ - public queryOrdersAndSampleSells( - orders: Array<{ - makerAddress: string; - takerAddress: string; - feeRecipientAddress: string; - senderAddress: string; - makerAssetAmount: BigNumber; - takerAssetAmount: BigNumber; - makerFee: BigNumber; - takerFee: BigNumber; - expirationTimeSeconds: BigNumber; - salt: BigNumber; - makerAssetData: string; - takerAssetData: string; - makerFeeAssetData: string; - takerFeeAssetData: string; - }>, - orderSignatures: string[], - sources: string[], - takerTokenAmounts: BigNumber[], - ): ContractFunctionObj<[BigNumber[], BigNumber[][]]> { - const self = (this as any) as IERC20BridgeSamplerContract; - assert.isArray('orders', orders); - assert.isArray('orderSignatures', orderSignatures); - assert.isArray('sources', sources); - assert.isArray('takerTokenAmounts', takerTokenAmounts); - const functionSignature = - 'queryOrdersAndSampleSells((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[],address[],uint256[])'; - - return { - async callAsync( - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise<[BigNumber[], BigNumber[][]]> { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { ...callData, data: this.getABIEncodedTransactionData() }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue<[BigNumber[], BigNumber[][]]>(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - orders, - orderSignatures, - sources, - takerTokenAmounts, - ]); - }, - }; - } - /** - * Query native orders and sample buy quotes on multiple DEXes at once. - * @param sources Address of each DEX. Passing in an unsupported DEX will - * throw. + * Sample buy quotes from Eth2Dai/Oasis. * @param takerToken Address of the taker token (what to sell). * @param makerToken Address of the maker token (what to buy). - * @param makerTokenAmounts Maker token buy amount for each sample. - * @returns takerTokenAmountsBySource Taker amounts sold for each source at each maker token amount. First indexed by source index, then sample index. + * @returns takerTokenAmounts Taker amounts sold at each maker token amount. */ - public sampleBuys( - sources: string[], + public sampleBuysFromEth2Dai( takerToken: string, makerToken: string, makerTokenAmounts: BigNumber[], - ): ContractFunctionObj { + ): ContractFunctionObj { const self = (this as any) as IERC20BridgeSamplerContract; - assert.isArray('sources', sources); assert.isString('takerToken', takerToken); assert.isString('makerToken', makerToken); assert.isArray('makerTokenAmounts', makerTokenAmounts); - const functionSignature = 'sampleBuys(address[],address,address,uint256[])'; + const functionSignature = 'sampleBuysFromEth2Dai(address,address,uint256[])'; return { - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); const rawCallResult = await self._performCallAsync( { ...callData, data: this.getABIEncodedTransactionData() }, @@ -1227,11 +702,10 @@ export class IERC20BridgeSamplerContract extends BaseContract { ); const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue(rawCallResult); + return abiEncoder.strictDecodeReturnValue(rawCallResult); }, getABIEncodedTransactionData(): string { return self._strictEncodeArguments(functionSignature, [ - sources, takerToken.toLowerCase(), makerToken.toLowerCase(), makerTokenAmounts, @@ -1240,29 +714,25 @@ export class IERC20BridgeSamplerContract extends BaseContract { }; } /** - * Sample sell quotes on multiple DEXes at once. - * @param sources Address of each DEX. Passing in an unsupported DEX will - * throw. + * Sample buy quotes from Uniswap. * @param takerToken Address of the taker token (what to sell). * @param makerToken Address of the maker token (what to buy). - * @param takerTokenAmounts Taker token sell amount for each sample. - * @returns makerTokenAmountsBySource Maker amounts bought for each source at each taker token amount. First indexed by source index, then sample index. + * @param makerTokenAmounts Maker token sell amount for each sample. + * @returns takerTokenAmounts Taker amounts sold at each maker token amount. */ - public sampleSells( - sources: string[], + public sampleBuysFromUniswap( takerToken: string, makerToken: string, - takerTokenAmounts: BigNumber[], - ): ContractFunctionObj { + makerTokenAmounts: BigNumber[], + ): ContractFunctionObj { const self = (this as any) as IERC20BridgeSamplerContract; - assert.isArray('sources', sources); assert.isString('takerToken', takerToken); assert.isString('makerToken', makerToken); - assert.isArray('takerTokenAmounts', takerTokenAmounts); - const functionSignature = 'sampleSells(address[],address,address,uint256[])'; + assert.isArray('makerTokenAmounts', makerTokenAmounts); + const functionSignature = 'sampleBuysFromUniswap(address,address,uint256[])'; return { - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); const rawCallResult = await self._performCallAsync( { ...callData, data: this.getABIEncodedTransactionData() }, @@ -1270,11 +740,124 @@ export class IERC20BridgeSamplerContract extends BaseContract { ); const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue(rawCallResult); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + makerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from Eth2Dai/Oasis. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromEth2Dai( + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as IERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromEth2Dai(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + takerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from Kyber. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromKyberNetwork( + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as IERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromKyberNetwork(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + takerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from Uniswap. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromUniswap( + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as IERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromUniswap(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); }, getABIEncodedTransactionData(): string { return self._strictEncodeArguments(functionSignature, [ - sources, takerToken.toLowerCase(), makerToken.toLowerCase(), takerTokenAmounts,