diff --git a/contracts/exchange-forwarder/contracts/src/Forwarder.sol b/contracts/exchange-forwarder/contracts/src/Forwarder.sol index b8c76f5345..fbf3754d91 100644 --- a/contracts/exchange-forwarder/contracts/src/Forwarder.sol +++ b/contracts/exchange-forwarder/contracts/src/Forwarder.sol @@ -151,6 +151,72 @@ contract Forwarder is _unwrapAndTransferEth(wethRemaining); } + /// @dev Purchases as much of orders' makerAssets as possible by selling the specified amount of ETH + /// accounting for order and forwarder fees. This functions throws if ethSellAmount was not reached. + /// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset. + /// @param ethSellAmount Desired amount of ETH to sell. + /// @param signatures Proofs that orders have been created by makers. + /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients. + /// @param feeRecipients Addresses that will receive ETH when orders are filled. + /// @return wethSpentAmount Amount of WETH spent on the given set of orders. + /// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders. + function marketSellAmountWithEth( + LibOrder.Order[] memory orders, + uint256 ethSellAmount, + bytes[] memory signatures, + uint256[] memory ethFeeAmounts, + address payable[] memory feeRecipients + ) + public + payable + returns ( + uint256 wethSpentAmount, + uint256 makerAssetAcquiredAmount + ) + { + if (ethSellAmount > msg.value) { + LibRichErrors.rrevert(LibForwarderRichErrors.CompleteSellFailedError( + ethSellAmount, + msg.value + )); + } + // Pay ETH affiliate fees to all feeRecipient addresses + uint256 wethRemaining = _transferEthFeesAndWrapRemaining( + ethFeeAmounts, + feeRecipients + ); + // Need enough remaining to ensure we can sell ethSellAmount + if (wethRemaining < ethSellAmount) { + LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError( + wethRemaining, + ethSellAmount + )); + } + // Spends up to ethSellAmount to fill orders, transfers purchased assets to msg.sender, + // and pays WETH order fees. + ( + wethSpentAmount, + makerAssetAcquiredAmount + ) = _marketSellExactAmountNoThrow( + orders, + ethSellAmount, + signatures + ); + // Ensure we sold the specified amount (note: wethSpentAmount includes fees) + if (wethSpentAmount < ethSellAmount) { + LibRichErrors.rrevert(LibForwarderRichErrors.CompleteSellFailedError( + ethSellAmount, + wethSpentAmount + )); + } + + // Calculate amount of WETH that hasn't been spent. + wethRemaining = wethRemaining.safeSub(wethSpentAmount); + + // Refund remaining ETH to msg.sender. + _unwrapAndTransferEth(wethRemaining); + } + /// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction. /// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can /// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees). diff --git a/contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol b/contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol index 1a7e2519ae..c255f624d4 100644 --- a/contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol +++ b/contracts/exchange-forwarder/contracts/src/MixinExchangeWrapper.sol @@ -53,6 +53,7 @@ contract MixinExchangeWrapper { // ")" // ))); bytes4 constant public EXCHANGE_V2_ORDER_ID = 0x770501f8; + bytes4 constant internal ERC20_BRIDGE_PROXY_ID = 0xdc1600f3; // solhint-disable var-name-mixedcase IExchange internal EXCHANGE; @@ -73,6 +74,12 @@ contract MixinExchangeWrapper { EXCHANGE_V2 = IExchangeV2(_exchangeV2); } + struct SellFillResults { + uint256 wethSpentAmount; + uint256 makerAssetAcquiredAmount; + uint256 protocolFeePaid; + } + /// @dev Fills the input order. /// Returns false if the transaction would otherwise revert. /// @param order Order struct containing order specifications. @@ -115,11 +122,16 @@ contract MixinExchangeWrapper { uint256 remainingTakerAssetFillAmount ) internal - returns ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ) + returns (SellFillResults memory sellFillResults) { + // If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance. + bytes4 makerAssetProxyId = order.makerAssetData.readBytes4(0); + address tokenAddress; + uint256 balanceBefore; + if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { + tokenAddress = order.makerAssetData.readAddress(16); + balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this)); + } // No taker fee or percentage fee if ( order.takerFee == 0 || @@ -132,11 +144,11 @@ contract MixinExchangeWrapper { signature ); - wethSpentAmount = singleFillResults.takerAssetFilledAmount - .safeAdd(singleFillResults.protocolFeePaid); + sellFillResults.wethSpentAmount = singleFillResults.takerAssetFilledAmount; + sellFillResults.protocolFeePaid = singleFillResults.protocolFeePaid; // Subtract fee from makerAssetFilledAmount for the net amount acquired. - makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount + sellFillResults.makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount .safeSub(singleFillResults.takerFeePaid); // WETH fee @@ -157,18 +169,27 @@ contract MixinExchangeWrapper { ); // WETH is also spent on the taker fee, so we add it here. - wethSpentAmount = singleFillResults.takerAssetFilledAmount - .safeAdd(singleFillResults.takerFeePaid) - .safeAdd(singleFillResults.protocolFeePaid); - - makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount; + sellFillResults.wethSpentAmount = singleFillResults.takerAssetFilledAmount + .safeAdd(singleFillResults.takerFeePaid); + sellFillResults.makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount; + sellFillResults.protocolFeePaid = singleFillResults.protocolFeePaid; // Unsupported fee } else { LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData)); } - return (wethSpentAmount, makerAssetAcquiredAmount); + // Account for the ERC20Bridge transfering more of the maker asset than expected. + if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { + uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this)); + sellFillResults.makerAssetAcquiredAmount = LibSafeMath.max256( + balanceAfter.safeSub(balanceBefore), + sellFillResults.makerAssetAcquiredAmount + ); + } + + order.makerAssetData.transferOut(sellFillResults.makerAssetAcquiredAmount); + return sellFillResults; } /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH has been sold by taker. @@ -189,7 +210,6 @@ contract MixinExchangeWrapper { ) { uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier()); - bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector; for (uint256 i = 0; i != orders.length; i++) { // Preemptively skip to avoid division by zero in _marketSellSingleOrder @@ -199,42 +219,27 @@ contract MixinExchangeWrapper { // The remaining amount of WETH to sell uint256 remainingTakerAssetFillAmount = wethSellAmount - .safeSub(totalWethSpentAmount) - .safeSub(_isV2Order(orders[i]) ? 0 : protocolFee); - - // If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance. - bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0); - address tokenAddress; - uint256 balanceBefore; - if (makerAssetProxyId == erc20BridgeProxyId) { - tokenAddress = orders[i].makerAssetData.readAddress(16); - balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this)); + .safeSub(totalWethSpentAmount); + uint256 currentProtocolFee = _isV2Order(orders[i]) ? 0 : protocolFee; + if (remainingTakerAssetFillAmount > currentProtocolFee) { + // Do not count the protocol fee as part of the fill amount. + remainingTakerAssetFillAmount = remainingTakerAssetFillAmount.safeSub(currentProtocolFee); + } else { + // Stop if we don't have at least enough ETH to pay another protocol fee. + break; } - ( - uint256 wethSpentAmount, - uint256 makerAssetAcquiredAmount - ) = _marketSellSingleOrder( + SellFillResults memory sellFillResults = _marketSellSingleOrder( orders[i], signatures[i], remainingTakerAssetFillAmount ); - // Account for the ERC20Bridge transfering more of the maker asset than expected. - if (makerAssetProxyId == erc20BridgeProxyId) { - uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this)); - makerAssetAcquiredAmount = LibSafeMath.max256( - balanceAfter.safeSub(balanceBefore), - makerAssetAcquiredAmount - ); - } - - orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount); - totalWethSpentAmount = totalWethSpentAmount - .safeAdd(wethSpentAmount); + .safeAdd(sellFillResults.wethSpentAmount) + .safeAdd(sellFillResults.protocolFeePaid); totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount - .safeAdd(makerAssetAcquiredAmount); + .safeAdd(sellFillResults.makerAssetAcquiredAmount); // Stop execution if the entire amount of WETH has been sold if (totalWethSpentAmount >= wethSellAmount) { @@ -243,6 +248,56 @@ contract MixinExchangeWrapper { } } + /// @dev Synchronously executes multiple calls of fillOrder until total amount of WETH (exclusive of protocol fee) + /// has been sold by taker. + /// @param orders Array of order specifications. + /// @param wethSellAmount Desired amount of WETH to sell. + /// @param signatures Proofs that orders have been signed by makers. + /// @return totalWethSpentAmount Total amount of WETH spent on the given orders. + /// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders. + function _marketSellExactAmountNoThrow( + LibOrder.Order[] memory orders, + uint256 wethSellAmount, + bytes[] memory signatures + ) + internal + returns ( + uint256 totalWethSpentAmount, + uint256 totalMakerAssetAcquiredAmount + ) + { + uint256 totalProtocolFeePaid; + + for (uint256 i = 0; i != orders.length; i++) { + // Preemptively skip to avoid division by zero in _marketSellSingleOrder + if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) { + continue; + } + + // The remaining amount of WETH to sell + uint256 remainingTakerAssetFillAmount = wethSellAmount + .safeSub(totalWethSpentAmount); + + SellFillResults memory sellFillResults = _marketSellSingleOrder( + orders[i], + signatures[i], + remainingTakerAssetFillAmount + ); + + totalWethSpentAmount = totalWethSpentAmount + .safeAdd(sellFillResults.wethSpentAmount); + totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount + .safeAdd(sellFillResults.makerAssetAcquiredAmount); + totalProtocolFeePaid = totalProtocolFeePaid.safeAdd(sellFillResults.protocolFeePaid); + + // Stop execution if the entire amount of WETH has been sold + if (totalWethSpentAmount >= wethSellAmount) { + break; + } + } + totalWethSpentAmount = totalWethSpentAmount.safeAdd(totalProtocolFeePaid); + } + /// @dev Executes a single call of fillOrder according to the makerAssetBuyAmount and /// the amount already bought. /// @param order A single order specification. @@ -338,8 +393,6 @@ contract MixinExchangeWrapper { uint256 totalMakerAssetAcquiredAmount ) { - bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector; - uint256 ordersLength = orders.length; for (uint256 i = 0; i != ordersLength; i++) { // Preemptively skip to avoid division by zero in _marketBuySingleOrder @@ -354,7 +407,7 @@ contract MixinExchangeWrapper { bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0); address tokenAddress; uint256 balanceBefore; - if (makerAssetProxyId == erc20BridgeProxyId) { + if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { tokenAddress = orders[i].makerAssetData.readAddress(16); balanceBefore = IERC20Token(tokenAddress).balanceOf(address(this)); } @@ -369,7 +422,7 @@ contract MixinExchangeWrapper { ); // Account for the ERC20Bridge transfering more of the maker asset than expected. - if (makerAssetProxyId == erc20BridgeProxyId) { + if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) { uint256 balanceAfter = IERC20Token(tokenAddress).balanceOf(address(this)); makerAssetAcquiredAmount = LibSafeMath.max256( balanceAfter.safeSub(balanceBefore), diff --git a/contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol b/contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol index 9fc9d7c527..44047e040b 100644 --- a/contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol +++ b/contracts/exchange-forwarder/contracts/src/libs/LibForwarderRichErrors.sol @@ -29,6 +29,10 @@ library LibForwarderRichErrors { bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR = 0x91353a0c; + // bytes4(keccak256("CompleteSellFailedError(uint256,uint256)")) + bytes4 internal constant COMPLETE_SELL_FAILED_ERROR_SELECTOR = + 0x450a0219; + // bytes4(keccak256("UnsupportedFeeError(bytes)")) bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR = 0x31360af1; @@ -61,6 +65,21 @@ library LibForwarderRichErrors { ); } + function CompleteSellFailedError( + uint256 expectedAssetSellAmount, + uint256 actualAssetSellAmount + ) + internal + pure + returns (bytes memory) + { + return abi.encodeWithSelector( + COMPLETE_SELL_FAILED_ERROR_SELECTOR, + expectedAssetSellAmount, + actualAssetSellAmount + ); + } + function UnsupportedFeeError( bytes memory takerFeeAssetData ) diff --git a/contracts/integrations/test/forwarder/forwarder_test.ts b/contracts/integrations/test/forwarder/forwarder_test.ts index 9062b51dc9..a797c34c78 100644 --- a/contracts/integrations/test/forwarder/forwarder_test.ts +++ b/contracts/integrations/test/forwarder/forwarder_test.ts @@ -448,6 +448,24 @@ blockchainTests('Forwarder integration tests', env => { }); }); }); + blockchainTests.resets('marketSellAmountWithEth', () => { + it('should fail if the supplied amount is not sold', async () => { + const order = await maker.signOrderAsync(); + const ethSellAmount = order.takerAssetAmount; + const revertError = new ExchangeForwarderRevertErrors.CompleteSellFailedError( + ethSellAmount, + order.takerAssetAmount.times(0.5).plus(DeploymentManager.protocolFee), + ); + await testFactory.marketSellAmountTestAsync([order], ethSellAmount, 0.5, { + revertError, + }); + }); + it('should sell the supplied amount', async () => { + const order = await maker.signOrderAsync(); + const ethSellAmount = order.takerAssetAmount; + await testFactory.marketSellAmountTestAsync([order], ethSellAmount, 1); + }); + }); blockchainTests.resets('marketBuyOrdersWithEth without extra fees', () => { it('should buy the exact amount of makerAsset in a single order', async () => { const order = await maker.signOrderAsync({ diff --git a/contracts/integrations/test/forwarder/forwarder_test_factory.ts b/contracts/integrations/test/forwarder/forwarder_test_factory.ts index a3c1467f45..c1ac563680 100644 --- a/contracts/integrations/test/forwarder/forwarder_test_factory.ts +++ b/contracts/integrations/test/forwarder/forwarder_test_factory.ts @@ -146,6 +146,51 @@ export class ForwarderTestFactory { await this._checkResultsAsync(txReceipt, orders, expectedOrderStatuses, expectedBalances); } } + public async marketSellAmountTestAsync( + orders: SignedOrder[], + ethSellAmount: BigNumber, + fractionalNumberOfOrdersToFill: number, + options: Partial = {}, + ): Promise { + const orderInfoBefore = await Promise.all( + orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()), + ); + const expectedOrderStatuses = orderInfoBefore.map((orderInfo, i) => + fractionalNumberOfOrdersToFill >= i + 1 && !(options.noopOrders || []).includes(i) + ? OrderStatus.FullyFilled + : orderInfo.orderStatus, + ); + + const { balances: expectedBalances, wethSpentAmount } = await this._simulateForwarderFillAsync( + orders, + orderInfoBefore, + fractionalNumberOfOrdersToFill, + options, + ); + + const forwarderFeeAmounts = options.forwarderFeeAmounts || []; + const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || []; + + const tx = this._forwarder + .marketSellAmountWithEth( + orders, + ethSellAmount, + orders.map(signedOrder => signedOrder.signature), + forwarderFeeAmounts, + forwarderFeeRecipientAddresses, + ) + .awaitTransactionSuccessAsync({ + value: wethSpentAmount.plus(BigNumber.sum(0, ...forwarderFeeAmounts)), + from: this._taker.address, + }); + + if (options.revertError !== undefined) { + await expect(tx).to.revertWith(options.revertError); + } else { + const txReceipt = await tx; + await this._checkResultsAsync(txReceipt, orders, expectedOrderStatuses, expectedBalances); + } + } private async _checkResultsAsync( txReceipt: TransactionReceiptWithDecodedLogs, diff --git a/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts b/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts index dce4e9c982..6284fcd2d9 100644 --- a/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts +++ b/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts @@ -76,7 +76,13 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase { .getABIEncodedTransactionData(); } else { calldataHexString = this._forwarder - .marketSellOrdersWithEth(orders, signatures, [feeAmount], [normalizedFeeRecipientAddress]) + .marketSellAmountWithEth( + orders, + quote.takerAssetFillAmount, + signatures, + [feeAmount], + [normalizedFeeRecipientAddress], + ) .getABIEncodedTransactionData(); } @@ -139,7 +145,7 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase { }); } else { txHash = await this._forwarder - .marketSellOrdersWithEth(orders, signatures, [feeAmount], [feeRecipient]) + .marketSellAmountWithEth(orders, quote.takerAssetFillAmount, signatures, [feeAmount], [feeRecipient]) .sendTransactionAsync({ from: finalTakerAddress, gas: gasLimit, diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index ccc04fb98b..e1739a3faa 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -25,6 +25,10 @@ { "note": "Add `dexForwarderBridge` addresses", "pr": 2525 + }, + { + "note": "Redeploy `Forwarder` on all networks", + "pr": 2521 } ] }, diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index 8dc0efb8b9..45e9820fa8 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -4,7 +4,7 @@ "exchange": "0x61935cbdd02287b511119ddb11aeb42f1593b7ef", "erc20Proxy": "0x95e6f48254609a6ee006f7d493c8e5fb97094cef", "erc721Proxy": "0xefc70a1b18c432bdc64b596838b4d138f6bc6cad", - "forwarder": "0x4aa817c6f383c8e8ae77301d18ce48efb16fd2be", + "forwarder": "0x6958f5e95332d93d21af0d7b9ca85b8212fee0a5", "zrxToken": "0xe41d2489571d322189246dafa5ebde1f4699f498", "etherToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "assetProxyOwner": "0xdffe798c7172dd6deb32baee68af322e8f495ce0", @@ -41,7 +41,7 @@ "exchange": "0xfb2dd2a1366de37f7241c83d47da58fd503e2c64", "assetProxyOwner": "0x0000000000000000000000000000000000000000", "zeroExGovernor": "0x53993733d41a88ae86f77a18a024e5548ee26579", - "forwarder": "0xe2bfd35306495d11e3c9db0d8de390cda24563cf", + "forwarder": "0x2127a60bedfba1c01857b09b8f24094049c48493", "coordinatorRegistry": "0x403cc23e88c17c4652fb904784d1af640a6722d9", "coordinator": "0x6ff734d96104965c9c1b0108f83abc46e6e501df", "multiAssetProxy": "0xab8fbd189c569ccdee3a4d929bb7f557be4028f6", @@ -74,7 +74,7 @@ "etherToken": "0xc778417e063141139fce010982780140aa0cd5ab", "assetProxyOwner": "0x0000000000000000000000000000000000000000", "zeroExGovernor": "0x3f46b98061a3e1e1f41dff296ec19402c298f8a9", - "forwarder": "0x263ccc190ccb1cb3342ab07e50f03edb2f05aa36", + "forwarder": "0x18571835c95a6d79b2f5c45b676ccd16f5fa34a1", "coordinatorRegistry": "0x1084b6a398e47907bae43fec3ff4b677db6e4fee", "coordinator": "0x70c5385ee5ee4629ef72abd169e888c8b4a12238", "multiAssetProxy": "0xb34cde0ad3a83d04abebc0b66e75196f22216621", @@ -107,7 +107,7 @@ "exchange": "0x4eacd0af335451709e1e7b570b8ea68edec8bc97", "assetProxyOwner": "0x0000000000000000000000000000000000000000", "zeroExGovernor": "0x6ff734d96104965c9c1b0108f83abc46e6e501df", - "forwarder": "0x263ccc190ccb1cb3342ab07e50f03edb2f05aa36", + "forwarder": "0x01c0ecf5d1a22de07a2de84c322bfa2b5435990e", "coordinatorRegistry": "0x09fb99968c016a3ff537bf58fb3d9fe55a7975d5", "coordinator": "0xd29e59e51e8ab5f94121efaeebd935ca4214e257", "multiAssetProxy": "0xf6313a772c222f51c28f2304c0703b8cf5428fd8", diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json index 58e3d872c5..53691f24f3 100644 --- a/packages/contract-artifacts/CHANGELOG.json +++ b/packages/contract-artifacts/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "Added `MaximumGasPrice` artifact", "pr": 2511 + }, + { + "note": "Added `Forwarder.marketSellAmountWithEth`", + "pr": 2521 } ] }, diff --git a/packages/contract-artifacts/artifacts/Forwarder.json b/packages/contract-artifacts/artifacts/Forwarder.json index 7b91d4a8e0..15499618ca 100644 --- a/packages/contract-artifacts/artifacts/Forwarder.json +++ b/packages/contract-artifacts/artifacts/Forwarder.json @@ -97,6 +97,44 @@ "stateMutability": "payable", "type": "function" }, + { + "constant": false, + "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": "uint256", "name": "ethSellAmount", "type": "uint256" }, + { "internalType": "bytes[]", "name": "signatures", "type": "bytes[]" }, + { "internalType": "uint256[]", "name": "ethFeeAmounts", "type": "uint256[]" }, + { "internalType": "address payable[]", "name": "feeRecipients", "type": "address[]" } + ], + "name": "marketSellAmountWithEth", + "outputs": [ + { "internalType": "uint256", "name": "wethSpentAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "makerAssetAcquiredAmount", "type": "uint256" } + ], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, { "constant": false, "inputs": [ @@ -212,6 +250,17 @@ }, "return": "wethSpentAmount Amount of WETH spent on the given set of orders.makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders." }, + "marketSellAmountWithEth((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],uint256,bytes[],uint256[],address[])": { + "details": "Purchases as much of orders' makerAssets as possible by selling the specified amount of ETH accounting for order and forwarder fees. This functions throws if ethSellAmount was not reached.", + "params": { + "ethFeeAmounts": "Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.", + "ethSellAmount": "Desired amount of ETH to sell.", + "feeRecipients": "Addresses that will receive ETH when orders are filled.", + "orders": "Array of order specifications used containing desired makerAsset and WETH as takerAsset.", + "signatures": "Proofs that orders have been created by makers." + }, + "return": "wethSpentAmount Amount of WETH spent on the given set of orders.makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders." + }, "marketSellOrdersWithEth((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[],uint256[],address[])": { "details": "Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent as possible, accounting for order and forwarder fees.", "params": { @@ -259,16 +308,16 @@ }, "evm": { "bytecode": { - "object": "0x60806040523480156200001157600080fd5b5060405162003c9d38038062003c9d833981016040819052620000349162000472565b60008054336001600160a01b031991821617909155600180549091166001600160a01b0383161790556040518390839082908490630f47261b60e41b9062000081908390602401620004e7565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217825251620000c191600291620003a0565b50604051630c0e082160e31b81526000906001600160a01b03841690636070410890620000fa90630f47261b60e41b9060040162000514565b60206040518083038186803b1580156200011357600080fd5b505afa15801562000128573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200014e919081019062000442565b90506001600160a01b038116620001895762000189620001786200036b60201b620007b11760201c565b6200039860201b620002d81760201c565b60015460405163095ea7b360e01b81526001600160a01b039091169063095ea7b390620001bf90849060001990600401620004fb565b602060405180830381600087803b158015620001da57600080fd5b505af1158015620001ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002159190810190620004c5565b506000836001600160a01b031663850a15016040518163ffffffff1660e01b815260040160206040518083038186803b1580156200025257600080fd5b505afa15801562000267573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200028d919081019062000442565b90506001600160a01b038116156200032d5760015460405163095ea7b360e01b81526001600160a01b039091169063095ea7b390620002d590849060001990600401620004fb565b602060405180830381600087803b158015620002f057600080fd5b505af115801562000305573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200032b9190810190620004c5565b505b5050600380546001600160a01b039586166001600160a01b031991821617909155600480549490951693169290921790925550620005429350505050565b6040805160048152602481019091526020810180516001600160e01b031663f3b96b8d60e01b1790525b90565b805160208201fd5b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003e357805160ff191683800117855562000413565b8280016001018555821562000413579182015b8281111562000413578251825591602001919060010190620003f6565b506200042192915062000425565b5090565b6200039591905b808211156200042157600081556001016200042c565b60006020828403121562000454578081fd5b81516001600160a01b03811681146200046b578182fd5b9392505050565b60008060006060848603121562000487578182fd5b8351620004948162000529565b6020850151909350620004a78162000529565b6040850151909250620004ba8162000529565b809150509250925092565b600060208284031215620004d7578081fd5b815180151581146200046b578182fd5b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160e01b031991909116815260200190565b6001600160a01b03811681146200053f57600080fd5b50565b61374b80620005526000396000f3fe6080604052600436106100bc5760003560e01c8063bc197c8111610074578063f23a6e611161004e578063f23a6e61146101e4578063f2fde38b14610204578063fc67bf1c14610224576100bc565b8063bc197c811461018d578063e0a5c949146101ba578063e196001b146101cf576100bc565b80638da5cb5b116100a55780638da5cb5b1461012e578063907e5cc3146101595780639e8323151461017a576100bc565b8063442026ed146100ee578063630f1e6c1461010e575b60015473ffffffffffffffffffffffffffffffffffffffff1633146100ec576100ec6100e733610239565b6102d8565b005b3480156100fa57600080fd5b506100ec610109366004613075565b6102e0565b34801561011a57600080fd5b506100ec6101293660046130b5565b6104ca565b34801561013a57600080fd5b50610143610520565b6040516101509190613246565b60405180910390f35b61016c610167366004612e77565b61053c565b604051610150929190613623565b61016c610188366004612f13565b610597565b34801561019957600080fd5b506101ad6101a8366004612d42565b6105f3565b604051610150919061334f565b3480156101c657600080fd5b506101ad610620565b3480156101db57600080fd5b506101ad610644565b3480156101f057600080fd5b506101ad6101ff366004612dfd565b610668565b34801561021057600080fd5b506100ec61021f366004612c72565b610693565b34801561023057600080fd5b506101ad610737565b60606308b1869860e01b826040516024016102549190613246565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b805160208201fd5b600061032c600084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff61075b169050565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000082168114156104c4576003546040517f6070410800000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff16906360704108906103d090859060040161334f565b60206040518083038186803b1580156103e857600080fd5b505afa1580156103fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104209190810190612c8e565b905073ffffffffffffffffffffffffffffffffffffffff8116610448576104486100e76107b1565b6000610494601087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff61080b169050565b90506104c181837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61084b565b50505b50505050565b6104d261090c565b61051b8184848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff610955169050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600080600061054b858561096b565b9050610558878288610ac1565b909350915080831115610572576105726100e78434610f28565b610582818463ffffffff610fca16565b905061058d81610fe9565b5094509492505050565b60008060006105a6858561096b565b90506105b38888886110a4565b9093509150808311156105cd576105cd6100e78434610f28565b6105dd818463ffffffff610fca16565b90506105e881610fe9565b509550959350505050565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b7ff23a6e610000000000000000000000000000000000000000000000000000000081565b7f770501f80000000000000000000000000000000000000000000000000000000081565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61069b61090c565b73ffffffffffffffffffffffffffffffffffffffff81166106c6576106c16100e76113e0565b610734565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35b50565b7fbc197c810000000000000000000000000000000000000000000000000000000081565b6000816004018351101561077c5761077c6100e76003855185600401611417565b5060208183018101519101907fffffffff00000000000000000000000000000000000000000000000000000000165b92915050565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff3b96b8d0000000000000000000000000000000000000000000000000000000017905290565b6000816014018351101561082c5761082c6100e76004855185601401611417565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b6040516060907f095ea7b300000000000000000000000000000000000000000000000000000000906108839085908590602401613329565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506104c484826114bd565b60005473ffffffffffffffffffffffffffffffffffffffff16331461095357600054610953906100e790339073ffffffffffffffffffffffffffffffffffffffff16611575565b565b6109678230338463ffffffff61159216565b5050565b81518151600091908114610987576109876100e78285516117cd565b34915060005b818114610a365760008582815181106109a257fe5b60200260200101519050808410156109c1576109c16100e782866117ea565b6109d1848263ffffffff610fca16565b93508482815181106109df57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610a2c573d6000803e3d6000fd5b505060010161098d565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610aa157600080fd5b505af1158015610ab5573d6000803e3d6000fd5b50505050505092915050565b6000806000610b76600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631ce4c78b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b3157600080fd5b505afa158015610b45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b699190810190613150565b3a9063ffffffff61180716565b90507fdc1600f30000000000000000000000000000000000000000000000000000000060005b87518114610f1d57878181518110610bb057fe5b60200260200101516080015160001480610be15750878181518110610bd157fe5b602002602001015160a001516000145b15610beb57610f15565b6000610c35610c0c8a8481518110610bff57fe5b6020026020010151611838565b610c165784610c19565b60005b610c298a8963ffffffff610fca16565b9063ffffffff610fca16565b90506000610c6560008b8581518110610c4a57fe5b6020026020010151610140015161075b90919063ffffffff16565b90506000807fffffffff000000000000000000000000000000000000000000000000000000008084169087161415610d6b57610cc360108d8781518110610ca857fe5b6020026020010151610140015161080b90919063ffffffff16565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190610d18903090600401613246565b60206040518083038186803b158015610d3057600080fd5b505afa158015610d44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d689190810190613150565b90505b600080610d9f8e8881518110610d7d57fe5b60200260200101518d8981518110610d9157fe5b6020026020010151886118ad565b91509150877bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610ead576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8616906370a0823190610e3e903090600401613246565b60206040518083038186803b158015610e5657600080fd5b505afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e8e9190810190613150565b9050610ea9610ea3828663ffffffff610fca16565b836119d7565b9150505b610ed8818f8981518110610ebd57fe5b6020026020010151610140015161095590919063ffffffff16565b610ee88b8363ffffffff6119ee16565b9a50610efa8a8263ffffffff6119ee16565b99508c8b10610f0e57505050505050610f1d565b5050505050505b600101610b9c565b505050935093915050565b606063cdcbed5d60e01b8383604051602401610f45929190613623565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905092915050565b600082821115610fe357610fe36100e760028585611a06565b50900390565b8015610734576001546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d9061104590849060040161361a565b600060405180830381600087803b15801561105f57600080fd5b505af1158015611073573d6000803e3d6000fd5b505060405133925083156108fc02915083906000818181858888f19350505050158015610967573d6000803e3d6000fd5b825160009081907fdc1600f30000000000000000000000000000000000000000000000000000000090825b8181146113c0578781815181106110e257fe5b60200260200101516080015160001480611113575087818151811061110357fe5b602002602001015160a001516000145b1561111d576113b8565b600061112f888663ffffffff610fca16565b9050600061114460008b8581518110610c4a57fe5b90506000807fffffffff00000000000000000000000000000000000000000000000000000000808416908816141561122f5761118760108d8781518110610ca857fe5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a08231906111dc903090600401613246565b60206040518083038186803b1580156111f457600080fd5b505afa158015611208573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061122c9190810190613150565b90505b6000806112638e888151811061124157fe5b60200260200101518d898151811061125557fe5b602002602001015188611a25565b91509150887bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561136b576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8616906370a0823190611302903090600401613246565b60206040518083038186803b15801561131a57600080fd5b505afa15801561132e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113529190810190613150565b9050611367610ea3828663ffffffff610fca16565b9150505b61137b818f8981518110610ebd57fe5b61138b8b8363ffffffff6119ee16565b9a5061139d8a8263ffffffff6119ee16565b99508c8a106113b1575050505050506113c0565b5050505050505b6001016110cf565b50858310156113d6576113d66100e78785611af7565b5050935093915050565b60408051808201909152600481527fe69edc3e00000000000000000000000000000000000000000000000000000000602082015290565b6060632800659560e01b848484604051602401611436939291906133b1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290505b9392505050565b600060608373ffffffffffffffffffffffffffffffffffffffff16836040516114e6919061322a565b6000604051808303816000865af19150503d8060008114611523576040519150601f19603f3d011682016040523d82523d6000602084013e611528565b606091505b5091509150811561156c578051611540575050610967565b80516020141561156c576000611557826000611b14565b9050806001141561156a57505050610967565b505b6104c4816102d8565b6060631de45ad160e01b8383604051602401610f45929190613267565b8061159c576104c4565b60006115ae858263ffffffff61075b16565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167ff47261b000000000000000000000000000000000000000000000000000000000148061164157507fffffffff0000000000000000000000000000000000000000000000000000000081167fdc1600f300000000000000000000000000000000000000000000000000000000145b1561165d576116588585858563ffffffff611b2016565b6117c6565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f025717920000000000000000000000000000000000000000000000000000000014156116b9576116588585858563ffffffff611b6a16565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fa7cb5fb7000000000000000000000000000000000000000000000000000000001415611715576116588585858563ffffffff611c3916565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611771576116588585858563ffffffff611d8f16565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fc339d10a00000000000000000000000000000000000000000000000000000000146117c6576117c66100e782611e23565b5050505050565b6060633ecb6ceb60e01b8383604051602401610f45929190613623565b606063ecf40fd960e01b8383604051602401610f45929190613623565b600082611816575060006107ab565b8282028284828161182357fe5b04146114b6576114b66100e760018686611a06565b60006003826101800151511180156107ab57506101808201517f770501f8000000000000000000000000000000000000000000000000000000009061188490600063ffffffff61075b16565b7fffffffff00000000000000000000000000000000000000000000000000000000161492915050565b6000808460e00151600014806118d257506118d2856101a00151866101400151611e3e565b15611929576118df612710565b6118ea868587611feb565b9050611907816080015182602001516119ee90919063ffffffff16565b60608201518251919450611921919063ffffffff610fca16565b9150506119cf565b61193d856101a00151866101600151611e3e565b156119be5760a085015160e086015160009161196a9161196490829063ffffffff6119ee16565b86612026565b9050611974612710565b61197f878388611feb565b90506119b081608001516119a4836060015184602001516119ee90919063ffffffff16565b9063ffffffff6119ee16565b905190935091506119cf9050565b6119cf6100e7866101a0015161205c565b935093915050565b6000818310156119e757816114b6565b5090919050565b6000828201838110156114b6576114b66100e7600086865b606063e946c1bb60e01b8484846040516024016114369392919061338f565b6000808460e0015160001480611a4a5750611a4a856101a00151866101600151611e3e565b15611a6457600061196a8660a00151876080015186612026565b611a78856101a00151866101400151611e3e565b156119be576000611aa28660a001516119648860e001518960800151610fca90919063ffffffff16565b9050611aac612710565b611ab7878388611feb565b9050611ad4816080015182602001516119ee90919063ffffffff16565b60608201518251919550611aee919063ffffffff610fca16565b925050506119cf565b60606391353a0c60e01b8383604051602401610f45929190613623565b60006114b68383612077565b6000611b3385601063ffffffff61080b16565b905073ffffffffffffffffffffffffffffffffffffffff8416301415611b5e576116588184846120a1565b6117c6818585856120d9565b80600114611b7e57611b7e6100e78261219c565b6000611b9185601063ffffffff61080b16565b90506000611ba686602463ffffffff611b1416565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd90611bff908890889086906004016132f8565b600060405180830381600087803b158015611c1957600080fd5b505af1158015611c2d573d6000803e3d6000fd5b50505050505050505050565b60006060806060611c57600489518a6121b79092919063ffffffff16565b806020019051611c6a9190810190612caa565b9350935093509350600082519050606081604051908082528060200260200182016040528015611ca4578160200160208202803883390190505b50905060005b828114611cf657611cd788868381518110611cc157fe5b602002602001015161180790919063ffffffff16565b828281518110611ce357fe5b6020908102919091010152600101611caa565b506040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690632eb2c2d690611d51908c908c908a9087908a9060040161328e565b600060405180830381600087803b158015611d6b57600080fd5b505af1158015611d7f573d6000803e3d6000fd5b5050505050505050505050505050565b606080611da960048751886121b79092919063ffffffff16565b806020019051611dbc9190810190612fc5565b8051919350915060005b818114611e1957611e11838281518110611ddc57fe5b60200260200101518888611e0c888681518110611df557fe5b60200260200101518a61180790919063ffffffff16565b611592565b600101611dc6565b5050505050505050565b6060637996a27160e01b82604051602401610254919061334f565b600080611e51848263ffffffff61075b16565b90506000611e65848263ffffffff61075b16565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fdc1600f3000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008416821480611efd57507fffffffff00000000000000000000000000000000000000000000000000000000848116908216145b8015611f5b57507fffffffff000000000000000000000000000000000000000000000000000000008381169083161480611f5b57507fffffffff00000000000000000000000000000000000000000000000000000000838116908216145b15611fc6576000611f7388601063ffffffff61080b16565b90506000611f8888601063ffffffff61080b16565b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161496505050505050506107ab565b611fd6878763ffffffff61223716565b9450505050506107ab565b5050505092915050565b611ff3612710565b611ffc84611838565b156120135761200c84848461225c565b90506114b6565b61201e8484846124b0565b949350505050565b600061201e8361205061204082600163ffffffff610fca16565b6119a4888763ffffffff61180716565b9063ffffffff61261d16565b60606331360af160e01b82604051602401610254919061337c565b60008160200183511015612098576120986100e76005855185602001611417565b50016020015190565b6040516060907fa9059cbb00000000000000000000000000000000000000000000000000000000906108839085908590602401613329565b6040516060907f23b872dd0000000000000000000000000000000000000000000000000000000090612113908690869086906024016132f8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506117c685826114bd565b606063baffa47460e01b82604051602401610254919061361a565b6060818311156121d0576121d06100e760008585611417565b83518211156121e9576121e96100e76001848751611417565b8282036040519080825280601f01601f191660200182016040528015612216576020820181803883390190505b5090506114b661222582612647565b8461222f87612647565b01835161264d565b6000815183511480156114b65750508051602091820120825192909101919091201490565b612264612710565b61226c61273f565b604051806101800160405280866000015173ffffffffffffffffffffffffffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152602001866040015173ffffffffffffffffffffffffffffffffffffffff168152602001866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866080015181526020018660a001518152602001600081526020016000815260200186610100015181526020018661012001518152602001866101400151815260200186610160015181525090506060600073ffffffffffffffffffffffffffffffffffffffff1663b4be83d5905060e01b82868660405160240161237f939291906133bf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600454915190925073ffffffffffffffffffffffffffffffffffffffff90911690600090606090839061243090869061322a565b6000604051808303816000865af19150503d806000811461246d576040519150601f19603f3d011682016040523d82523d6000602084013e612472565b606091505b509150915081156124a457805160801461248857fe5b8080602001905161249c9190810190613168565b602088015286525b50505050509392505050565b6124b8612710565b6040516060907f9b44d55600000000000000000000000000000000000000000000000000000000906124f2908790879087906024016134df565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600354915190925073ffffffffffffffffffffffffffffffffffffffff9091169060009060609083906125a390869061322a565b6000604051808303816000865af19150503d80600081146125e0576040519150601f19603f3d011682016040523d82523d6000602084013e6125e5565b606091505b5091509150811561261257805160a0146125fb57fe5b8080602001905161260f91908101906130ff565b94505b505050509392505050565b600081612633576126336100e760038585611a06565b600082848161263e57fe5b04949350505050565b60200190565b6020811015612677576001816020036101000a03801983511681855116808217865250505061051b565b828214156126845761051b565b828211156126be5760208103905080820181840181515b828510156126b657845186526020958601959094019361269b565b90525061051b565b60208103905080820181840183515b8186121561270757825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe092830192909101906126cd565b85525050505050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b80356107ab816136e6565b600082601f830112612813578081fd5b813561282661282182613658565b613631565b81815291506020808301908481018184028601820187101561284757600080fd5b60005b8481101561286f57813561285d816136e6565b8452928201929082019060010161284a565b505050505092915050565b600082601f83011261288a578081fd5b813561289861282182613658565b8181529150602080830190840160005b83811015611fe1576128c08760208435890101612bd7565b835260209283019291909101906001016128a8565b600082601f8301126128e5578081fd5b81356128f361282182613658565b818152915060208083019084810160005b8481101561286f57813587016101c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838c0301121561294457600080fd5b61294d81613631565b6129598b8785016127f8565b81526129688b604085016127f8565b868201526129798b606085016127f8565b604082015261298b8b608085016127f8565b606082015260a0830135608082015260c083013560a082015260e083013560c08201526101008084013560e0830152610120808501358284015261014091508185013581840152506101608085013567ffffffffffffffff808211156129f057600080fd5b6129fe8f8b848a0101612bd7565b84860152610180935083870135915080821115612a1a57600080fd5b612a288f8b848a0101612bd7565b838601526101a0925082870135915080821115612a4457600080fd5b612a528f8b848a0101612bd7565b8486015285870135935080841115612a6957600080fd5b5050612a798d8984880101612bd7565b9083015250865250509282019290820190600101612904565b60008083601f840112612aa3578182fd5b50813567ffffffffffffffff811115612aba578182fd5b6020830191508360208083028501011115612ad457600080fd5b9250929050565b600082601f830112612aeb578081fd5b8151612af961282182613658565b818152915060208083019084810181840286018201871015612b1a57600080fd5b60005b8481101561286f57815184529282019290820190600101612b1d565b600082601f830112612b49578081fd5b8135612b5761282182613658565b818152915060208083019084810181840286018201871015612b7857600080fd5b60005b8481101561286f57813584529282019290820190600101612b7b565b60008083601f840112612ba8578182fd5b50813567ffffffffffffffff811115612bbf578182fd5b602083019150836020828501011115612ad457600080fd5b600082601f830112612be7578081fd5b8135612bf561282182613678565b9150808252836020828501011115612c0c57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612c35578081fd5b8151612c4361282182613678565b9150808252836020828501011115612c5a57600080fd5b612c6b8160208401602086016136ba565b5092915050565b600060208284031215612c83578081fd5b81356114b6816136e6565b600060208284031215612c9f578081fd5b81516114b6816136e6565b60008060008060808587031215612cbf578283fd5b8451612cca816136e6565b602086015190945067ffffffffffffffff80821115612ce7578485fd5b612cf388838901612adb565b94506040870151915080821115612d08578384fd5b612d1488838901612adb565b93506060870151915080821115612d29578283fd5b50612d3687828801612c25565b91505092959194509250565b60008060008060008060008060a0898b031215612d5d578586fd5b8835612d68816136e6565b97506020890135612d78816136e6565b9650604089013567ffffffffffffffff80821115612d94578788fd5b612da08c838d01612a92565b909850965060608b0135915080821115612db8578586fd5b612dc48c838d01612a92565b909650945060808b0135915080821115612ddc578384fd5b50612de98b828c01612b97565b999c989b5096995094979396929594505050565b60008060008060008060a08789031215612e15578384fd5b8635612e20816136e6565b95506020870135612e30816136e6565b94506040870135935060608701359250608087013567ffffffffffffffff811115612e59578283fd5b612e6589828a01612b97565b979a9699509497509295939492505050565b60008060008060808587031215612e8c578182fd5b843567ffffffffffffffff80821115612ea3578384fd5b612eaf888389016128d5565b95506020870135915080821115612ec4578384fd5b612ed08883890161287a565b94506040870135915080821115612ee5578384fd5b612ef188838901612b39565b93506060870135915080821115612f06578283fd5b50612d3687828801612803565b600080600080600060a08688031215612f2a578283fd5b853567ffffffffffffffff80821115612f41578485fd5b612f4d89838a016128d5565b9650602088013595506040880135915080821115612f69578485fd5b612f7589838a0161287a565b94506060880135915080821115612f8a578283fd5b612f9689838a01612b39565b93506080880135915080821115612fab578283fd5b50612fb888828901612803565b9150509295509295909350565b60008060408385031215612fd7578182fd5b825167ffffffffffffffff80821115612fee578384fd5b612ffa86838701612adb565b9350602091508185015181811115613010578384fd5b85019050601f81018613613022578283fd5b805161303061282182613658565b81815283810190838501865b84811015613065576130538b888451890101612c25565b8452928601929086019060010161303c565b5096999098509650505050505050565b60008060208385031215613087578182fd5b823567ffffffffffffffff81111561309d578283fd5b6130a985828601612b97565b90969095509350505050565b6000806000604084860312156130c9578081fd5b833567ffffffffffffffff8111156130df578182fd5b6130eb86828701612b97565b909790965060209590950135949350505050565b600060a08284031215613110578081fd5b61311a60a0613631565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b600060208284031215613161578081fd5b5051919050565b6000806040838503121561317a578182fd5b505080516020909101519092909150565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845260208401935060208301825b828110156131d65781518652602095860195909101906001016131b8565b5093949350505050565b600081518084526131f88160208601602086016136ba565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000825161323c8184602087016136ba565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a060408301526132c760a08301866131a5565b82810360608401526132d981866131a5565b83810360808501526132eb81866131e0565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b6000602082526114b660208301846131e0565b606081016004851061339d57fe5b938152602081019290925260409091015290565b606081016008851061339d57fe5b6000606082526133d360608301865161318b565b60208501516133e5608084018261318b565b5060408501516133f860a084018261318b565b50606085015161340b60c084018261318b565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e088015192506101408381870152828901519350610160925083838701528189015193506101809150838287015280890151935050806101a08601525061347e6101e08501836131e0565b8188015192507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0858203016101c08601526134b981846131e0565b91505085602085015283810360408501526134d481866131e0565b979650505050505050565b6000606082526134f360608301865161318b565b6020850151613505608084018261318b565b50604085015161351860a084018261318b565b50606085015161352b60c084018261318b565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e0880151925061014083818701528289015193506101609250838387015281890151935061018091508382870152808901519350506101c06101a081818801526135a16102208801866131e0565b848b015195507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa094508488820301838901526135dd81876131e0565b925050828a0151945083878303016101e08801526135fb82866131e0565b9250808a01519450505081858203016102008601526134b981846131e0565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561365057600080fd5b604052919050565b600067ffffffffffffffff82111561366e578081fd5b5060209081020190565b600067ffffffffffffffff82111561368e578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110156136d55781810151838201526020016136bd565b838111156104c45750506000910152565b73ffffffffffffffffffffffffffffffffffffffff8116811461073457600080fdfea365627a7a72315820ebedf6ba0823da75dd29d928186748ec6baa07f40f145a90097baa22da29b56a6c6578706572696d656e74616cf564736f6c63430005100040" + "object": "0x60806040523480156200001157600080fd5b5060405162003f2c38038062003f2c833981016040819052620000349162000472565b60008054336001600160a01b031991821617909155600180549091166001600160a01b0383161790556040518390839082908490630f47261b60e41b9062000081908390602401620004e7565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217825251620000c191600291620003a0565b50604051630c0e082160e31b81526000906001600160a01b03841690636070410890620000fa90630f47261b60e41b9060040162000514565b60206040518083038186803b1580156200011357600080fd5b505afa15801562000128573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200014e919081019062000442565b90506001600160a01b038116620001895762000189620001786200036b60201b6200082f1760201c565b6200039860201b620002f61760201c565b60015460405163095ea7b360e01b81526001600160a01b039091169063095ea7b390620001bf90849060001990600401620004fb565b602060405180830381600087803b158015620001da57600080fd5b505af1158015620001ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002159190810190620004c5565b506000836001600160a01b031663850a15016040518163ffffffff1660e01b815260040160206040518083038186803b1580156200025257600080fd5b505afa15801562000267573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200028d919081019062000442565b90506001600160a01b038116156200032d5760015460405163095ea7b360e01b81526001600160a01b039091169063095ea7b390620002d590849060001990600401620004fb565b602060405180830381600087803b158015620002f057600080fd5b505af115801562000305573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200032b9190810190620004c5565b505b5050600380546001600160a01b039586166001600160a01b031991821617909155600480549490951693169290921790925550620005429350505050565b6040805160048152602481019091526020810180516001600160e01b031663f3b96b8d60e01b1790525b90565b805160208201fd5b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003e357805160ff191683800117855562000413565b8280016001018555821562000413579182015b8281111562000413578251825591602001919060010190620003f6565b506200042192915062000425565b5090565b6200039591905b808211156200042157600081556001016200042c565b60006020828403121562000454578081fd5b81516001600160a01b03811681146200046b578182fd5b9392505050565b60008060006060848603121562000487578182fd5b8351620004948162000529565b6020850151909350620004a78162000529565b6040850151909250620004ba8162000529565b809150509250925092565b600060208284031215620004d7578081fd5b815180151581146200046b578182fd5b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160e01b031991909116815260200190565b6001600160a01b03811681146200053f57600080fd5b50565b6139da80620005526000396000f3fe6080604052600436106100c75760003560e01c8063bc197c8111610074578063f23a6e611161004e578063f23a6e6114610202578063f2fde38b14610222578063fc67bf1c14610242576100c7565b8063bc197c81146101ab578063e0a5c949146101d8578063e196001b146101ed576100c7565b8063907e5cc3116100a5578063907e5cc314610164578063939ce6ba146101855780639e83231514610198576100c7565b8063442026ed146100f9578063630f1e6c146101195780638da5cb5b14610139575b60015473ffffffffffffffffffffffffffffffffffffffff1633146100f7576100f76100f233610257565b6102f6565b005b34801561010557600080fd5b506100f7610114366004613304565b6102fe565b34801561012557600080fd5b506100f7610134366004613344565b6104e8565b34801561014557600080fd5b5061014e61053e565b60405161015b91906134d5565b60405180910390f35b610177610172366004613106565b61055a565b60405161015b9291906138b2565b6101776101933660046131a2565b6105b5565b6101776101a63660046131a2565b61063b565b3480156101b757600080fd5b506101cb6101c6366004612fd1565b610671565b60405161015b91906135de565b3480156101e457600080fd5b506101cb61069e565b3480156101f957600080fd5b506101cb6106c2565b34801561020e57600080fd5b506101cb61021d36600461308c565b6106e6565b34801561022e57600080fd5b506100f761023d366004612f01565b610711565b34801561024e57600080fd5b506101cb6107b5565b60606308b1869860e01b8260405160240161027291906134d5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b805160208201fd5b600061034a600084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff6107d9169050565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000082168114156104e2576003546040517f6070410800000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff16906360704108906103ee9085906004016135de565b60206040518083038186803b15801561040657600080fd5b505afa15801561041a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061043e9190810190612f1d565b905073ffffffffffffffffffffffffffffffffffffffff8116610466576104666100f261082f565b60006104b2601087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff610889169050565b90506104df81837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108c9565b50505b50505050565b6104f061098a565b6105398184848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff6109d3169050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600080600061056985856109e9565b9050610576878288610b3f565b909350915080831115610590576105906100f28434610d53565b6105a0818463ffffffff610df516565b90506105ab81610e14565b5094509492505050565b600080348611156105cd576105cd6100f28734610ecf565b60006105d985856109e9565b9050868110156105f0576105f06100f28289610d53565b6105fb888888610eec565b909350915086831015610615576106156100f28885610ecf565b610625818463ffffffff610df516565b905061063081610e14565b509550959350505050565b600080600061064a85856109e9565b905061065788888861100d565b909350915080831115610615576106156100f28434610d53565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b7ff23a6e610000000000000000000000000000000000000000000000000000000081565b7f770501f80000000000000000000000000000000000000000000000000000000081565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61071961098a565b73ffffffffffffffffffffffffffffffffffffffff81166107445761073f6100f261139f565b6107b2565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35b50565b7fbc197c810000000000000000000000000000000000000000000000000000000081565b600081600401835110156107fa576107fa6100f260038551856004016113d6565b5060208183018101519101907fffffffff00000000000000000000000000000000000000000000000000000000165b92915050565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff3b96b8d0000000000000000000000000000000000000000000000000000000017905290565b600081601401835110156108aa576108aa6100f260048551856014016113d6565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b6040516060907f095ea7b3000000000000000000000000000000000000000000000000000000009061090190859085906024016135b8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506104e2848261147c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109d1576000546109d1906100f290339073ffffffffffffffffffffffffffffffffffffffff16611534565b565b6109e58230338463ffffffff61155116565b5050565b81518151600091908114610a0557610a056100f282855161178c565b34915060005b818114610ab4576000858281518110610a2057fe5b6020026020010151905080841015610a3f57610a3f6100f282866117a9565b610a4f848263ffffffff610df516565b9350848281518110610a5d57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610aaa573d6000803e3d6000fd5b5050600101610a0b565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610b1f57600080fd5b505af1158015610b33573d6000803e3d6000fd5b50505050505092915050565b6000806000610bf4600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631ce4c78b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610baf57600080fd5b505afa158015610bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610be791908101906133df565b3a9063ffffffff6117c616565b905060005b86518114610d4957868181518110610c0d57fe5b60200260200101516080015160001480610c3e5750868181518110610c2e57fe5b602002602001015160a001516000145b15610c4857610d41565b6000610c5a878663ffffffff610df516565b90506000610c7a898481518110610c6d57fe5b60200260200101516117f7565b610c845783610c87565b60005b905080821115610ca857610ca1828263ffffffff610df516565b9150610caf565b5050610d49565b610cb761297e565b610ce88a8581518110610cc657fe5b6020026020010151898681518110610cda57fe5b60200260200101518561186c565b60408101518151919250610d1391610d07908a9063ffffffff611bde16565b9063ffffffff611bde16565b9650610d2c816020015187611bde90919063ffffffff16565b9550888710610d3d57505050610d49565b5050505b600101610bf9565b5050935093915050565b606063cdcbed5d60e01b8383604051602401610d709291906138b2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905092915050565b600082821115610e0e57610e0e6100f260028585611bf6565b50900390565b80156107b2576001546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d90610e709084906004016138a9565b600060405180830381600087803b158015610e8a57600080fd5b505af1158015610e9e573d6000803e3d6000fd5b505060405133925083156108fc02915083906000818181858888f193505050501580156109e5573d6000803e3d6000fd5b606063450a021960e01b8383604051602401610d709291906138b2565b60008080805b86518114610ff157868181518110610f0657fe5b60200260200101516080015160001480610f375750868181518110610f2757fe5b602002602001015160a001516000145b15610f4157610fe9565b6000610f53878663ffffffff610df516565b9050610f5d61297e565b610f8e898481518110610f6c57fe5b6020026020010151888581518110610f8057fe5b60200260200101518461186c565b8051909150610fa490879063ffffffff611bde16565b9550610fbd816020015186611bde90919063ffffffff16565b9450610fd6816040015185611bde90919063ffffffff16565b9350878610610fe6575050610ff1565b50505b600101610ef2565b50611002838263ffffffff611bde16565b925050935093915050565b82516000908190815b8181146113805786818151811061102957fe5b6020026020010151608001516000148061105a575086818151811061104a57fe5b602002602001015160a001516000145b1561106457611378565b6000611076878563ffffffff610df516565b905060006110a660008a858151811061108b57fe5b602002602001015161014001516107d990919063ffffffff16565b90506000807fffffffff0000000000000000000000000000000000000000000000000000000083167fdc1600f30000000000000000000000000000000000000000000000000000000014156111c95761112160108c878151811061110657fe5b6020026020010151610140015161088990919063ffffffff16565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a08231906111769030906004016134d5565b60206040518083038186803b15801561118e57600080fd5b505afa1580156111a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111c691908101906133df565b90505b6000806111fd8d88815181106111db57fe5b60200260200101518c89815181106111ef57fe5b602002602001015188611c15565b90925090507fffffffff0000000000000000000000000000000000000000000000000000000085167fdc1600f3000000000000000000000000000000000000000000000000000000001415611310576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8616906370a08231906112a19030906004016134d5565b60206040518083038186803b1580156112b957600080fd5b505afa1580156112cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112f191908101906133df565b905061130c611306828663ffffffff610df516565b83611d4e565b9150505b61133b818e898151811061132057fe5b602002602001015161014001516109d390919063ffffffff16565b61134b8a8363ffffffff611bde16565b995061135d898263ffffffff611bde16565b98508b891061137157505050505050611380565b5050505050505b600101611016565b5084821015611396576113966100f28684611d65565b50935093915050565b60408051808201909152600481527fe69edc3e00000000000000000000000000000000000000000000000000000000602082015290565b6060632800659560e01b8484846040516024016113f593929190613640565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290505b9392505050565b600060608373ffffffffffffffffffffffffffffffffffffffff16836040516114a591906134b9565b6000604051808303816000865af19150503d80600081146114e2576040519150601f19603f3d011682016040523d82523d6000602084013e6114e7565b606091505b5091509150811561152b5780516114ff5750506109e5565b80516020141561152b576000611516826000611d82565b90508060011415611529575050506109e5565b505b6104e2816102f6565b6060631de45ad160e01b8383604051602401610d709291906134f6565b8061155b576104e2565b600061156d858263ffffffff6107d916565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167ff47261b000000000000000000000000000000000000000000000000000000000148061160057507fffffffff0000000000000000000000000000000000000000000000000000000081167fdc1600f300000000000000000000000000000000000000000000000000000000145b1561161c576116178585858563ffffffff611d8e16565b611785565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f02571792000000000000000000000000000000000000000000000000000000001415611678576116178585858563ffffffff611dd816565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156116d4576116178585858563ffffffff611ea716565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611730576116178585858563ffffffff611ffd16565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fc339d10a0000000000000000000000000000000000000000000000000000000014611785576117856100f282612091565b5050505050565b6060633ecb6ceb60e01b8383604051602401610d709291906138b2565b606063ecf40fd960e01b8383604051602401610d709291906138b2565b6000826117d557506000610829565b828202828482816117e257fe5b0414611475576114756100f260018686611bf6565b600060038261018001515111801561082957506101808201517f770501f8000000000000000000000000000000000000000000000000000000009061184390600063ffffffff6107d916565b7fffffffff00000000000000000000000000000000000000000000000000000000161492915050565b61187461297e565b61014084015160009061188d908263ffffffff6107d916565b90506000807fffffffff0000000000000000000000000000000000000000000000000000000083167fdc1600f300000000000000000000000000000000000000000000000000000000141561199b576101408701516118f390601063ffffffff61088916565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a08231906119489030906004016134d5565b60206040518083038186803b15801561196057600080fd5b505afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061199891908101906133df565b90505b60e087015115806119bb57506119bb876101a001518861014001516120ac565b15611a09576119c861299f565b6119d3888789612259565b6020810151865260808101516040870152606081015181519192506119fe919063ffffffff610df516565b602086015250611aa5565b611a1d876101a001518861016001516120ac565b15611a945760a087015160e0880151600091611a4a91611a4490829063ffffffff611bde16565b88612294565b9050611a5461299f565b611a5f89838a612259565b9050611a7c81606001518260200151611bde90919063ffffffff16565b86528051602087015260800151604086015250611aa5565b611aa56100f2886101a001516122ca565b7fffffffff0000000000000000000000000000000000000000000000000000000083167fdc1600f3000000000000000000000000000000000000000000000000000000001415611bba576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190611b449030906004016134d5565b60206040518083038186803b158015611b5c57600080fd5b505afa158015611b70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b9491908101906133df565b9050611bb3611ba9828463ffffffff610df516565b8660200151611d4e565b6020860152505b6020840151610140880151611bd49163ffffffff6109d316565b5050509392505050565b600082820183811015611475576114756100f2600086865b606063e946c1bb60e01b8484846040516024016113f59392919061361e565b6000808460e0015160001480611c3a5750611c3a856101a001518661016001516120ac565b15611c9c576000611c548660a00151876080015186612294565b9050611c5e61299f565b611c69878388612259565b9050611c8e8160800151610d0783606001518460200151611bde90919063ffffffff16565b90519093509150611d469050565b611cb0856101a001518661014001516120ac565b15611d35576000611ce08660a00151611cda8860e001518960800151610df590919063ffffffff16565b86612294565b9050611cea61299f565b611cf5878388612259565b9050611d1281608001518260200151611bde90919063ffffffff16565b60608201518251919550611d2c919063ffffffff610df516565b92505050611d46565b611d466100f2866101a001516122ca565b935093915050565b600081831015611d5e5781611475565b5090919050565b60606391353a0c60e01b8383604051602401610d709291906138b2565b600061147583836122e5565b6000611da185601063ffffffff61088916565b905073ffffffffffffffffffffffffffffffffffffffff8416301415611dcc5761161781848461230f565b61178581858585612347565b80600114611dec57611dec6100f28261240a565b6000611dff85601063ffffffff61088916565b90506000611e1486602463ffffffff611d8216565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd90611e6d90889088908690600401613587565b600060405180830381600087803b158015611e8757600080fd5b505af1158015611e9b573d6000803e3d6000fd5b50505050505050505050565b60006060806060611ec5600489518a6124259092919063ffffffff16565b806020019051611ed89190810190612f39565b9350935093509350600082519050606081604051908082528060200260200182016040528015611f12578160200160208202803883390190505b50905060005b828114611f6457611f4588868381518110611f2f57fe5b60200260200101516117c690919063ffffffff16565b828281518110611f5157fe5b6020908102919091010152600101611f18565b506040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690632eb2c2d690611fbf908c908c908a9087908a9060040161351d565b600060405180830381600087803b158015611fd957600080fd5b505af1158015611fed573d6000803e3d6000fd5b5050505050505050505050505050565b60608061201760048751886124259092919063ffffffff16565b80602001905161202a9190810190613254565b8051919350915060005b8181146120875761207f83828151811061204a57fe5b6020026020010151888861207a88868151811061206357fe5b60200260200101518a6117c690919063ffffffff16565b611551565b600101612034565b5050505050505050565b6060637996a27160e01b8260405160240161027291906135de565b6000806120bf848263ffffffff6107d916565b905060006120d3848263ffffffff6107d916565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fdc1600f3000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000841682148061216b57507fffffffff00000000000000000000000000000000000000000000000000000000848116908216145b80156121c957507fffffffff0000000000000000000000000000000000000000000000000000000083811690831614806121c957507fffffffff00000000000000000000000000000000000000000000000000000000838116908216145b156122345760006121e188601063ffffffff61088916565b905060006121f688601063ffffffff61088916565b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149650505050505050610829565b612244878763ffffffff6124a516565b945050505050610829565b5050505092915050565b61226161299f565b61226a846117f7565b156122815761227a8484846124ca565b9050611475565b61228c84848461271e565b949350505050565b600061228c836122be6122ae82600163ffffffff610df516565b610d07888763ffffffff6117c616565b9063ffffffff61288b16565b60606331360af160e01b82604051602401610272919061360b565b60008160200183511015612306576123066100f260058551856020016113d6565b50016020015190565b6040516060907fa9059cbb000000000000000000000000000000000000000000000000000000009061090190859085906024016135b8565b6040516060907f23b872dd000000000000000000000000000000000000000000000000000000009061238190869086908690602401613587565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611785858261147c565b606063baffa47460e01b8260405160240161027291906138a9565b60608183111561243e5761243e6100f2600085856113d6565b8351821115612457576124576100f260018487516113d6565b8282036040519080825280601f01601f191660200182016040528015612484576020820181803883390190505b509050611475612493826128b5565b8461249d876128b5565b0183516128bb565b6000815183511480156114755750508051602091820120825192909101919091201490565b6124d261299f565b6124da6129ce565b604051806101800160405280866000015173ffffffffffffffffffffffffffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152602001866040015173ffffffffffffffffffffffffffffffffffffffff168152602001866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866080015181526020018660a001518152602001600081526020016000815260200186610100015181526020018661012001518152602001866101400151815260200186610160015181525090506060600073ffffffffffffffffffffffffffffffffffffffff1663b4be83d5905060e01b8286866040516024016125ed9392919061364e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600454915190925073ffffffffffffffffffffffffffffffffffffffff90911690600090606090839061269e9086906134b9565b6000604051808303816000865af19150503d80600081146126db576040519150601f19603f3d011682016040523d82523d6000602084013e6126e0565b606091505b509150915081156127125780516080146126f657fe5b8080602001905161270a91908101906133f7565b602088015286525b50505050509392505050565b61272661299f565b6040516060907f9b44d55600000000000000000000000000000000000000000000000000000000906127609087908790879060240161376e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600354915190925073ffffffffffffffffffffffffffffffffffffffff9091169060009060609083906128119086906134b9565b6000604051808303816000865af19150503d806000811461284e576040519150601f19603f3d011682016040523d82523d6000602084013e612853565b606091505b5091509150811561288057805160a01461286957fe5b8080602001905161287d919081019061338e565b94505b505050509392505050565b6000816128a1576128a16100f260038585611bf6565b60008284816128ac57fe5b04949350505050565b60200190565b60208110156128e5576001816020036101000a038019835116818551168082178652505050610539565b828214156128f257610539565b8282111561292c5760208103905080820181840181515b82851015612924578451865260209586019590940193612909565b905250610539565b60208103905080820181840183515b8186121561297557825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0928301929091019061293b565b85525050505050565b60405180606001604052806000815260200160008152602001600081525090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b803561082981613975565b600082601f830112612aa2578081fd5b8135612ab5612ab0826138e7565b6138c0565b818152915060208083019084810181840286018201871015612ad657600080fd5b60005b84811015612afe578135612aec81613975565b84529282019290820190600101612ad9565b505050505092915050565b600082601f830112612b19578081fd5b8135612b27612ab0826138e7565b8181529150602080830190840160005b8381101561224f57612b4f8760208435890101612e66565b83526020928301929190910190600101612b37565b600082601f830112612b74578081fd5b8135612b82612ab0826138e7565b818152915060208083019084810160005b84811015612afe57813587016101c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838c03011215612bd357600080fd5b612bdc816138c0565b612be88b878501612a87565b8152612bf78b60408501612a87565b86820152612c088b60608501612a87565b6040820152612c1a8b60808501612a87565b606082015260a0830135608082015260c083013560a082015260e083013560c08201526101008084013560e0830152610120808501358284015261014091508185013581840152506101608085013567ffffffffffffffff80821115612c7f57600080fd5b612c8d8f8b848a0101612e66565b84860152610180935083870135915080821115612ca957600080fd5b612cb78f8b848a0101612e66565b838601526101a0925082870135915080821115612cd357600080fd5b612ce18f8b848a0101612e66565b8486015285870135935080841115612cf857600080fd5b5050612d088d8984880101612e66565b9083015250865250509282019290820190600101612b93565b60008083601f840112612d32578182fd5b50813567ffffffffffffffff811115612d49578182fd5b6020830191508360208083028501011115612d6357600080fd5b9250929050565b600082601f830112612d7a578081fd5b8151612d88612ab0826138e7565b818152915060208083019084810181840286018201871015612da957600080fd5b60005b84811015612afe57815184529282019290820190600101612dac565b600082601f830112612dd8578081fd5b8135612de6612ab0826138e7565b818152915060208083019084810181840286018201871015612e0757600080fd5b60005b84811015612afe57813584529282019290820190600101612e0a565b60008083601f840112612e37578182fd5b50813567ffffffffffffffff811115612e4e578182fd5b602083019150836020828501011115612d6357600080fd5b600082601f830112612e76578081fd5b8135612e84612ab082613907565b9150808252836020828501011115612e9b57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612ec4578081fd5b8151612ed2612ab082613907565b9150808252836020828501011115612ee957600080fd5b612efa816020840160208601613949565b5092915050565b600060208284031215612f12578081fd5b813561147581613975565b600060208284031215612f2e578081fd5b815161147581613975565b60008060008060808587031215612f4e578283fd5b8451612f5981613975565b602086015190945067ffffffffffffffff80821115612f76578485fd5b612f8288838901612d6a565b94506040870151915080821115612f97578384fd5b612fa388838901612d6a565b93506060870151915080821115612fb8578283fd5b50612fc587828801612eb4565b91505092959194509250565b60008060008060008060008060a0898b031215612fec578586fd5b8835612ff781613975565b9750602089013561300781613975565b9650604089013567ffffffffffffffff80821115613023578788fd5b61302f8c838d01612d21565b909850965060608b0135915080821115613047578586fd5b6130538c838d01612d21565b909650945060808b013591508082111561306b578384fd5b506130788b828c01612e26565b999c989b5096995094979396929594505050565b60008060008060008060a087890312156130a4578384fd5b86356130af81613975565b955060208701356130bf81613975565b94506040870135935060608701359250608087013567ffffffffffffffff8111156130e8578283fd5b6130f489828a01612e26565b979a9699509497509295939492505050565b6000806000806080858703121561311b578182fd5b843567ffffffffffffffff80821115613132578384fd5b61313e88838901612b64565b95506020870135915080821115613153578384fd5b61315f88838901612b09565b94506040870135915080821115613174578384fd5b61318088838901612dc8565b93506060870135915080821115613195578283fd5b50612fc587828801612a92565b600080600080600060a086880312156131b9578283fd5b853567ffffffffffffffff808211156131d0578485fd5b6131dc89838a01612b64565b96506020880135955060408801359150808211156131f8578485fd5b61320489838a01612b09565b94506060880135915080821115613219578283fd5b61322589838a01612dc8565b9350608088013591508082111561323a578283fd5b5061324788828901612a92565b9150509295509295909350565b60008060408385031215613266578182fd5b825167ffffffffffffffff8082111561327d578384fd5b61328986838701612d6a565b935060209150818501518181111561329f578384fd5b85019050601f810186136132b1578283fd5b80516132bf612ab0826138e7565b81815283810190838501865b848110156132f4576132e28b888451890101612eb4565b845292860192908601906001016132cb565b5096999098509650505050505050565b60008060208385031215613316578182fd5b823567ffffffffffffffff81111561332c578283fd5b61333885828601612e26565b90969095509350505050565b600080600060408486031215613358578081fd5b833567ffffffffffffffff81111561336e578182fd5b61337a86828701612e26565b909790965060209590950135949350505050565b600060a0828403121561339f578081fd5b6133a960a06138c0565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b6000602082840312156133f0578081fd5b5051919050565b60008060408385031215613409578182fd5b505080516020909101519092909150565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845260208401935060208301825b82811015613465578151865260209586019590910190600101613447565b5093949350505050565b60008151808452613487816020860160208601613949565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082516134cb818460208701613949565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a0604083015261355660a0830186613434565b82810360608401526135688186613434565b838103608085015261357a818661346f565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b600060208252611475602083018461346f565b606081016004851061362c57fe5b938152602081019290925260409091015290565b606081016008851061362c57fe5b60006060825261366260608301865161341a565b6020850151613674608084018261341a565b50604085015161368760a084018261341a565b50606085015161369a60c084018261341a565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e088015192506101408381870152828901519350610160925083838701528189015193506101809150838287015280890151935050806101a08601525061370d6101e085018361346f565b8188015192507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0858203016101c0860152613748818461346f565b9150508560208501528381036040850152613763818661346f565b979650505050505050565b60006060825261378260608301865161341a565b6020850151613794608084018261341a565b5060408501516137a760a084018261341a565b5060608501516137ba60c084018261341a565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e0880151925061014083818701528289015193506101609250838387015281890151935061018091508382870152808901519350506101c06101a0818188015261383061022088018661346f565b848b015195507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0945084888203018389015261386c818761346f565b925050828a0151945083878303016101e088015261388a828661346f565b9250808a0151945050508185820301610200860152613748818461346f565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156138df57600080fd5b604052919050565b600067ffffffffffffffff8211156138fd578081fd5b5060209081020190565b600067ffffffffffffffff82111561391d578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b8381101561396457818101518382015260200161394c565b838111156104e25750506000910152565b73ffffffffffffffffffffffffffffffffffffffff811681146107b257600080fdfea365627a7a7231582044b5b700e71da9b34ea681113c5c2d7dc51a60db3338ae1b4863b61744fd81b86c6578706572696d656e74616cf564736f6c63430005110040" }, "deployedBytecode": { - "object": "0x6080604052600436106100bc5760003560e01c8063bc197c8111610074578063f23a6e611161004e578063f23a6e61146101e4578063f2fde38b14610204578063fc67bf1c14610224576100bc565b8063bc197c811461018d578063e0a5c949146101ba578063e196001b146101cf576100bc565b80638da5cb5b116100a55780638da5cb5b1461012e578063907e5cc3146101595780639e8323151461017a576100bc565b8063442026ed146100ee578063630f1e6c1461010e575b60015473ffffffffffffffffffffffffffffffffffffffff1633146100ec576100ec6100e733610239565b6102d8565b005b3480156100fa57600080fd5b506100ec610109366004613075565b6102e0565b34801561011a57600080fd5b506100ec6101293660046130b5565b6104ca565b34801561013a57600080fd5b50610143610520565b6040516101509190613246565b60405180910390f35b61016c610167366004612e77565b61053c565b604051610150929190613623565b61016c610188366004612f13565b610597565b34801561019957600080fd5b506101ad6101a8366004612d42565b6105f3565b604051610150919061334f565b3480156101c657600080fd5b506101ad610620565b3480156101db57600080fd5b506101ad610644565b3480156101f057600080fd5b506101ad6101ff366004612dfd565b610668565b34801561021057600080fd5b506100ec61021f366004612c72565b610693565b34801561023057600080fd5b506101ad610737565b60606308b1869860e01b826040516024016102549190613246565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b805160208201fd5b600061032c600084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff61075b169050565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000082168114156104c4576003546040517f6070410800000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff16906360704108906103d090859060040161334f565b60206040518083038186803b1580156103e857600080fd5b505afa1580156103fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104209190810190612c8e565b905073ffffffffffffffffffffffffffffffffffffffff8116610448576104486100e76107b1565b6000610494601087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff61080b169050565b90506104c181837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61084b565b50505b50505050565b6104d261090c565b61051b8184848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff610955169050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600080600061054b858561096b565b9050610558878288610ac1565b909350915080831115610572576105726100e78434610f28565b610582818463ffffffff610fca16565b905061058d81610fe9565b5094509492505050565b60008060006105a6858561096b565b90506105b38888886110a4565b9093509150808311156105cd576105cd6100e78434610f28565b6105dd818463ffffffff610fca16565b90506105e881610fe9565b509550959350505050565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b7ff23a6e610000000000000000000000000000000000000000000000000000000081565b7f770501f80000000000000000000000000000000000000000000000000000000081565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61069b61090c565b73ffffffffffffffffffffffffffffffffffffffff81166106c6576106c16100e76113e0565b610734565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35b50565b7fbc197c810000000000000000000000000000000000000000000000000000000081565b6000816004018351101561077c5761077c6100e76003855185600401611417565b5060208183018101519101907fffffffff00000000000000000000000000000000000000000000000000000000165b92915050565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff3b96b8d0000000000000000000000000000000000000000000000000000000017905290565b6000816014018351101561082c5761082c6100e76004855185601401611417565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b6040516060907f095ea7b300000000000000000000000000000000000000000000000000000000906108839085908590602401613329565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506104c484826114bd565b60005473ffffffffffffffffffffffffffffffffffffffff16331461095357600054610953906100e790339073ffffffffffffffffffffffffffffffffffffffff16611575565b565b6109678230338463ffffffff61159216565b5050565b81518151600091908114610987576109876100e78285516117cd565b34915060005b818114610a365760008582815181106109a257fe5b60200260200101519050808410156109c1576109c16100e782866117ea565b6109d1848263ffffffff610fca16565b93508482815181106109df57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610a2c573d6000803e3d6000fd5b505060010161098d565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610aa157600080fd5b505af1158015610ab5573d6000803e3d6000fd5b50505050505092915050565b6000806000610b76600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631ce4c78b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b3157600080fd5b505afa158015610b45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b699190810190613150565b3a9063ffffffff61180716565b90507fdc1600f30000000000000000000000000000000000000000000000000000000060005b87518114610f1d57878181518110610bb057fe5b60200260200101516080015160001480610be15750878181518110610bd157fe5b602002602001015160a001516000145b15610beb57610f15565b6000610c35610c0c8a8481518110610bff57fe5b6020026020010151611838565b610c165784610c19565b60005b610c298a8963ffffffff610fca16565b9063ffffffff610fca16565b90506000610c6560008b8581518110610c4a57fe5b6020026020010151610140015161075b90919063ffffffff16565b90506000807fffffffff000000000000000000000000000000000000000000000000000000008084169087161415610d6b57610cc360108d8781518110610ca857fe5b6020026020010151610140015161080b90919063ffffffff16565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190610d18903090600401613246565b60206040518083038186803b158015610d3057600080fd5b505afa158015610d44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d689190810190613150565b90505b600080610d9f8e8881518110610d7d57fe5b60200260200101518d8981518110610d9157fe5b6020026020010151886118ad565b91509150877bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610ead576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8616906370a0823190610e3e903090600401613246565b60206040518083038186803b158015610e5657600080fd5b505afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e8e9190810190613150565b9050610ea9610ea3828663ffffffff610fca16565b836119d7565b9150505b610ed8818f8981518110610ebd57fe5b6020026020010151610140015161095590919063ffffffff16565b610ee88b8363ffffffff6119ee16565b9a50610efa8a8263ffffffff6119ee16565b99508c8b10610f0e57505050505050610f1d565b5050505050505b600101610b9c565b505050935093915050565b606063cdcbed5d60e01b8383604051602401610f45929190613623565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905092915050565b600082821115610fe357610fe36100e760028585611a06565b50900390565b8015610734576001546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d9061104590849060040161361a565b600060405180830381600087803b15801561105f57600080fd5b505af1158015611073573d6000803e3d6000fd5b505060405133925083156108fc02915083906000818181858888f19350505050158015610967573d6000803e3d6000fd5b825160009081907fdc1600f30000000000000000000000000000000000000000000000000000000090825b8181146113c0578781815181106110e257fe5b60200260200101516080015160001480611113575087818151811061110357fe5b602002602001015160a001516000145b1561111d576113b8565b600061112f888663ffffffff610fca16565b9050600061114460008b8581518110610c4a57fe5b90506000807fffffffff00000000000000000000000000000000000000000000000000000000808416908816141561122f5761118760108d8781518110610ca857fe5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a08231906111dc903090600401613246565b60206040518083038186803b1580156111f457600080fd5b505afa158015611208573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061122c9190810190613150565b90505b6000806112638e888151811061124157fe5b60200260200101518d898151811061125557fe5b602002602001015188611a25565b91509150887bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561136b576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8616906370a0823190611302903090600401613246565b60206040518083038186803b15801561131a57600080fd5b505afa15801561132e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113529190810190613150565b9050611367610ea3828663ffffffff610fca16565b9150505b61137b818f8981518110610ebd57fe5b61138b8b8363ffffffff6119ee16565b9a5061139d8a8263ffffffff6119ee16565b99508c8a106113b1575050505050506113c0565b5050505050505b6001016110cf565b50858310156113d6576113d66100e78785611af7565b5050935093915050565b60408051808201909152600481527fe69edc3e00000000000000000000000000000000000000000000000000000000602082015290565b6060632800659560e01b848484604051602401611436939291906133b1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290505b9392505050565b600060608373ffffffffffffffffffffffffffffffffffffffff16836040516114e6919061322a565b6000604051808303816000865af19150503d8060008114611523576040519150601f19603f3d011682016040523d82523d6000602084013e611528565b606091505b5091509150811561156c578051611540575050610967565b80516020141561156c576000611557826000611b14565b9050806001141561156a57505050610967565b505b6104c4816102d8565b6060631de45ad160e01b8383604051602401610f45929190613267565b8061159c576104c4565b60006115ae858263ffffffff61075b16565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167ff47261b000000000000000000000000000000000000000000000000000000000148061164157507fffffffff0000000000000000000000000000000000000000000000000000000081167fdc1600f300000000000000000000000000000000000000000000000000000000145b1561165d576116588585858563ffffffff611b2016565b6117c6565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f025717920000000000000000000000000000000000000000000000000000000014156116b9576116588585858563ffffffff611b6a16565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fa7cb5fb7000000000000000000000000000000000000000000000000000000001415611715576116588585858563ffffffff611c3916565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611771576116588585858563ffffffff611d8f16565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fc339d10a00000000000000000000000000000000000000000000000000000000146117c6576117c66100e782611e23565b5050505050565b6060633ecb6ceb60e01b8383604051602401610f45929190613623565b606063ecf40fd960e01b8383604051602401610f45929190613623565b600082611816575060006107ab565b8282028284828161182357fe5b04146114b6576114b66100e760018686611a06565b60006003826101800151511180156107ab57506101808201517f770501f8000000000000000000000000000000000000000000000000000000009061188490600063ffffffff61075b16565b7fffffffff00000000000000000000000000000000000000000000000000000000161492915050565b6000808460e00151600014806118d257506118d2856101a00151866101400151611e3e565b15611929576118df612710565b6118ea868587611feb565b9050611907816080015182602001516119ee90919063ffffffff16565b60608201518251919450611921919063ffffffff610fca16565b9150506119cf565b61193d856101a00151866101600151611e3e565b156119be5760a085015160e086015160009161196a9161196490829063ffffffff6119ee16565b86612026565b9050611974612710565b61197f878388611feb565b90506119b081608001516119a4836060015184602001516119ee90919063ffffffff16565b9063ffffffff6119ee16565b905190935091506119cf9050565b6119cf6100e7866101a0015161205c565b935093915050565b6000818310156119e757816114b6565b5090919050565b6000828201838110156114b6576114b66100e7600086865b606063e946c1bb60e01b8484846040516024016114369392919061338f565b6000808460e0015160001480611a4a5750611a4a856101a00151866101600151611e3e565b15611a6457600061196a8660a00151876080015186612026565b611a78856101a00151866101400151611e3e565b156119be576000611aa28660a001516119648860e001518960800151610fca90919063ffffffff16565b9050611aac612710565b611ab7878388611feb565b9050611ad4816080015182602001516119ee90919063ffffffff16565b60608201518251919550611aee919063ffffffff610fca16565b925050506119cf565b60606391353a0c60e01b8383604051602401610f45929190613623565b60006114b68383612077565b6000611b3385601063ffffffff61080b16565b905073ffffffffffffffffffffffffffffffffffffffff8416301415611b5e576116588184846120a1565b6117c6818585856120d9565b80600114611b7e57611b7e6100e78261219c565b6000611b9185601063ffffffff61080b16565b90506000611ba686602463ffffffff611b1416565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd90611bff908890889086906004016132f8565b600060405180830381600087803b158015611c1957600080fd5b505af1158015611c2d573d6000803e3d6000fd5b50505050505050505050565b60006060806060611c57600489518a6121b79092919063ffffffff16565b806020019051611c6a9190810190612caa565b9350935093509350600082519050606081604051908082528060200260200182016040528015611ca4578160200160208202803883390190505b50905060005b828114611cf657611cd788868381518110611cc157fe5b602002602001015161180790919063ffffffff16565b828281518110611ce357fe5b6020908102919091010152600101611caa565b506040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690632eb2c2d690611d51908c908c908a9087908a9060040161328e565b600060405180830381600087803b158015611d6b57600080fd5b505af1158015611d7f573d6000803e3d6000fd5b5050505050505050505050505050565b606080611da960048751886121b79092919063ffffffff16565b806020019051611dbc9190810190612fc5565b8051919350915060005b818114611e1957611e11838281518110611ddc57fe5b60200260200101518888611e0c888681518110611df557fe5b60200260200101518a61180790919063ffffffff16565b611592565b600101611dc6565b5050505050505050565b6060637996a27160e01b82604051602401610254919061334f565b600080611e51848263ffffffff61075b16565b90506000611e65848263ffffffff61075b16565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fdc1600f3000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008416821480611efd57507fffffffff00000000000000000000000000000000000000000000000000000000848116908216145b8015611f5b57507fffffffff000000000000000000000000000000000000000000000000000000008381169083161480611f5b57507fffffffff00000000000000000000000000000000000000000000000000000000838116908216145b15611fc6576000611f7388601063ffffffff61080b16565b90506000611f8888601063ffffffff61080b16565b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161496505050505050506107ab565b611fd6878763ffffffff61223716565b9450505050506107ab565b5050505092915050565b611ff3612710565b611ffc84611838565b156120135761200c84848461225c565b90506114b6565b61201e8484846124b0565b949350505050565b600061201e8361205061204082600163ffffffff610fca16565b6119a4888763ffffffff61180716565b9063ffffffff61261d16565b60606331360af160e01b82604051602401610254919061337c565b60008160200183511015612098576120986100e76005855185602001611417565b50016020015190565b6040516060907fa9059cbb00000000000000000000000000000000000000000000000000000000906108839085908590602401613329565b6040516060907f23b872dd0000000000000000000000000000000000000000000000000000000090612113908690869086906024016132f8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506117c685826114bd565b606063baffa47460e01b82604051602401610254919061361a565b6060818311156121d0576121d06100e760008585611417565b83518211156121e9576121e96100e76001848751611417565b8282036040519080825280601f01601f191660200182016040528015612216576020820181803883390190505b5090506114b661222582612647565b8461222f87612647565b01835161264d565b6000815183511480156114b65750508051602091820120825192909101919091201490565b612264612710565b61226c61273f565b604051806101800160405280866000015173ffffffffffffffffffffffffffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152602001866040015173ffffffffffffffffffffffffffffffffffffffff168152602001866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866080015181526020018660a001518152602001600081526020016000815260200186610100015181526020018661012001518152602001866101400151815260200186610160015181525090506060600073ffffffffffffffffffffffffffffffffffffffff1663b4be83d5905060e01b82868660405160240161237f939291906133bf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600454915190925073ffffffffffffffffffffffffffffffffffffffff90911690600090606090839061243090869061322a565b6000604051808303816000865af19150503d806000811461246d576040519150601f19603f3d011682016040523d82523d6000602084013e612472565b606091505b509150915081156124a457805160801461248857fe5b8080602001905161249c9190810190613168565b602088015286525b50505050509392505050565b6124b8612710565b6040516060907f9b44d55600000000000000000000000000000000000000000000000000000000906124f2908790879087906024016134df565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600354915190925073ffffffffffffffffffffffffffffffffffffffff9091169060009060609083906125a390869061322a565b6000604051808303816000865af19150503d80600081146125e0576040519150601f19603f3d011682016040523d82523d6000602084013e6125e5565b606091505b5091509150811561261257805160a0146125fb57fe5b8080602001905161260f91908101906130ff565b94505b505050509392505050565b600081612633576126336100e760038585611a06565b600082848161263e57fe5b04949350505050565b60200190565b6020811015612677576001816020036101000a03801983511681855116808217865250505061051b565b828214156126845761051b565b828211156126be5760208103905080820181840181515b828510156126b657845186526020958601959094019361269b565b90525061051b565b60208103905080820181840183515b8186121561270757825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe092830192909101906126cd565b85525050505050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b80356107ab816136e6565b600082601f830112612813578081fd5b813561282661282182613658565b613631565b81815291506020808301908481018184028601820187101561284757600080fd5b60005b8481101561286f57813561285d816136e6565b8452928201929082019060010161284a565b505050505092915050565b600082601f83011261288a578081fd5b813561289861282182613658565b8181529150602080830190840160005b83811015611fe1576128c08760208435890101612bd7565b835260209283019291909101906001016128a8565b600082601f8301126128e5578081fd5b81356128f361282182613658565b818152915060208083019084810160005b8481101561286f57813587016101c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838c0301121561294457600080fd5b61294d81613631565b6129598b8785016127f8565b81526129688b604085016127f8565b868201526129798b606085016127f8565b604082015261298b8b608085016127f8565b606082015260a0830135608082015260c083013560a082015260e083013560c08201526101008084013560e0830152610120808501358284015261014091508185013581840152506101608085013567ffffffffffffffff808211156129f057600080fd5b6129fe8f8b848a0101612bd7565b84860152610180935083870135915080821115612a1a57600080fd5b612a288f8b848a0101612bd7565b838601526101a0925082870135915080821115612a4457600080fd5b612a528f8b848a0101612bd7565b8486015285870135935080841115612a6957600080fd5b5050612a798d8984880101612bd7565b9083015250865250509282019290820190600101612904565b60008083601f840112612aa3578182fd5b50813567ffffffffffffffff811115612aba578182fd5b6020830191508360208083028501011115612ad457600080fd5b9250929050565b600082601f830112612aeb578081fd5b8151612af961282182613658565b818152915060208083019084810181840286018201871015612b1a57600080fd5b60005b8481101561286f57815184529282019290820190600101612b1d565b600082601f830112612b49578081fd5b8135612b5761282182613658565b818152915060208083019084810181840286018201871015612b7857600080fd5b60005b8481101561286f57813584529282019290820190600101612b7b565b60008083601f840112612ba8578182fd5b50813567ffffffffffffffff811115612bbf578182fd5b602083019150836020828501011115612ad457600080fd5b600082601f830112612be7578081fd5b8135612bf561282182613678565b9150808252836020828501011115612c0c57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612c35578081fd5b8151612c4361282182613678565b9150808252836020828501011115612c5a57600080fd5b612c6b8160208401602086016136ba565b5092915050565b600060208284031215612c83578081fd5b81356114b6816136e6565b600060208284031215612c9f578081fd5b81516114b6816136e6565b60008060008060808587031215612cbf578283fd5b8451612cca816136e6565b602086015190945067ffffffffffffffff80821115612ce7578485fd5b612cf388838901612adb565b94506040870151915080821115612d08578384fd5b612d1488838901612adb565b93506060870151915080821115612d29578283fd5b50612d3687828801612c25565b91505092959194509250565b60008060008060008060008060a0898b031215612d5d578586fd5b8835612d68816136e6565b97506020890135612d78816136e6565b9650604089013567ffffffffffffffff80821115612d94578788fd5b612da08c838d01612a92565b909850965060608b0135915080821115612db8578586fd5b612dc48c838d01612a92565b909650945060808b0135915080821115612ddc578384fd5b50612de98b828c01612b97565b999c989b5096995094979396929594505050565b60008060008060008060a08789031215612e15578384fd5b8635612e20816136e6565b95506020870135612e30816136e6565b94506040870135935060608701359250608087013567ffffffffffffffff811115612e59578283fd5b612e6589828a01612b97565b979a9699509497509295939492505050565b60008060008060808587031215612e8c578182fd5b843567ffffffffffffffff80821115612ea3578384fd5b612eaf888389016128d5565b95506020870135915080821115612ec4578384fd5b612ed08883890161287a565b94506040870135915080821115612ee5578384fd5b612ef188838901612b39565b93506060870135915080821115612f06578283fd5b50612d3687828801612803565b600080600080600060a08688031215612f2a578283fd5b853567ffffffffffffffff80821115612f41578485fd5b612f4d89838a016128d5565b9650602088013595506040880135915080821115612f69578485fd5b612f7589838a0161287a565b94506060880135915080821115612f8a578283fd5b612f9689838a01612b39565b93506080880135915080821115612fab578283fd5b50612fb888828901612803565b9150509295509295909350565b60008060408385031215612fd7578182fd5b825167ffffffffffffffff80821115612fee578384fd5b612ffa86838701612adb565b9350602091508185015181811115613010578384fd5b85019050601f81018613613022578283fd5b805161303061282182613658565b81815283810190838501865b84811015613065576130538b888451890101612c25565b8452928601929086019060010161303c565b5096999098509650505050505050565b60008060208385031215613087578182fd5b823567ffffffffffffffff81111561309d578283fd5b6130a985828601612b97565b90969095509350505050565b6000806000604084860312156130c9578081fd5b833567ffffffffffffffff8111156130df578182fd5b6130eb86828701612b97565b909790965060209590950135949350505050565b600060a08284031215613110578081fd5b61311a60a0613631565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b600060208284031215613161578081fd5b5051919050565b6000806040838503121561317a578182fd5b505080516020909101519092909150565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845260208401935060208301825b828110156131d65781518652602095860195909101906001016131b8565b5093949350505050565b600081518084526131f88160208601602086016136ba565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000825161323c8184602087016136ba565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a060408301526132c760a08301866131a5565b82810360608401526132d981866131a5565b83810360808501526132eb81866131e0565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b6000602082526114b660208301846131e0565b606081016004851061339d57fe5b938152602081019290925260409091015290565b606081016008851061339d57fe5b6000606082526133d360608301865161318b565b60208501516133e5608084018261318b565b5060408501516133f860a084018261318b565b50606085015161340b60c084018261318b565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e088015192506101408381870152828901519350610160925083838701528189015193506101809150838287015280890151935050806101a08601525061347e6101e08501836131e0565b8188015192507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0858203016101c08601526134b981846131e0565b91505085602085015283810360408501526134d481866131e0565b979650505050505050565b6000606082526134f360608301865161318b565b6020850151613505608084018261318b565b50604085015161351860a084018261318b565b50606085015161352b60c084018261318b565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e0880151925061014083818701528289015193506101609250838387015281890151935061018091508382870152808901519350506101c06101a081818801526135a16102208801866131e0565b848b015195507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa094508488820301838901526135dd81876131e0565b925050828a0151945083878303016101e08801526135fb82866131e0565b9250808a01519450505081858203016102008601526134b981846131e0565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561365057600080fd5b604052919050565b600067ffffffffffffffff82111561366e578081fd5b5060209081020190565b600067ffffffffffffffff82111561368e578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110156136d55781810151838201526020016136bd565b838111156104c45750506000910152565b73ffffffffffffffffffffffffffffffffffffffff8116811461073457600080fdfea365627a7a72315820ebedf6ba0823da75dd29d928186748ec6baa07f40f145a90097baa22da29b56a6c6578706572696d656e74616cf564736f6c63430005100040" + "object": "0x6080604052600436106100c75760003560e01c8063bc197c8111610074578063f23a6e611161004e578063f23a6e6114610202578063f2fde38b14610222578063fc67bf1c14610242576100c7565b8063bc197c81146101ab578063e0a5c949146101d8578063e196001b146101ed576100c7565b8063907e5cc3116100a5578063907e5cc314610164578063939ce6ba146101855780639e83231514610198576100c7565b8063442026ed146100f9578063630f1e6c146101195780638da5cb5b14610139575b60015473ffffffffffffffffffffffffffffffffffffffff1633146100f7576100f76100f233610257565b6102f6565b005b34801561010557600080fd5b506100f7610114366004613304565b6102fe565b34801561012557600080fd5b506100f7610134366004613344565b6104e8565b34801561014557600080fd5b5061014e61053e565b60405161015b91906134d5565b60405180910390f35b610177610172366004613106565b61055a565b60405161015b9291906138b2565b6101776101933660046131a2565b6105b5565b6101776101a63660046131a2565b61063b565b3480156101b757600080fd5b506101cb6101c6366004612fd1565b610671565b60405161015b91906135de565b3480156101e457600080fd5b506101cb61069e565b3480156101f957600080fd5b506101cb6106c2565b34801561020e57600080fd5b506101cb61021d36600461308c565b6106e6565b34801561022e57600080fd5b506100f761023d366004612f01565b610711565b34801561024e57600080fd5b506101cb6107b5565b60606308b1869860e01b8260405160240161027291906134d5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b805160208201fd5b600061034a600084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff6107d9169050565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000082168114156104e2576003546040517f6070410800000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff16906360704108906103ee9085906004016135de565b60206040518083038186803b15801561040657600080fd5b505afa15801561041a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061043e9190810190612f1d565b905073ffffffffffffffffffffffffffffffffffffffff8116610466576104666100f261082f565b60006104b2601087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff610889169050565b90506104df81837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108c9565b50505b50505050565b6104f061098a565b6105398184848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff6109d3169050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600080600061056985856109e9565b9050610576878288610b3f565b909350915080831115610590576105906100f28434610d53565b6105a0818463ffffffff610df516565b90506105ab81610e14565b5094509492505050565b600080348611156105cd576105cd6100f28734610ecf565b60006105d985856109e9565b9050868110156105f0576105f06100f28289610d53565b6105fb888888610eec565b909350915086831015610615576106156100f28885610ecf565b610625818463ffffffff610df516565b905061063081610e14565b509550959350505050565b600080600061064a85856109e9565b905061065788888861100d565b909350915080831115610615576106156100f28434610d53565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b7ff23a6e610000000000000000000000000000000000000000000000000000000081565b7f770501f80000000000000000000000000000000000000000000000000000000081565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61071961098a565b73ffffffffffffffffffffffffffffffffffffffff81166107445761073f6100f261139f565b6107b2565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35b50565b7fbc197c810000000000000000000000000000000000000000000000000000000081565b600081600401835110156107fa576107fa6100f260038551856004016113d6565b5060208183018101519101907fffffffff00000000000000000000000000000000000000000000000000000000165b92915050565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff3b96b8d0000000000000000000000000000000000000000000000000000000017905290565b600081601401835110156108aa576108aa6100f260048551856014016113d6565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b6040516060907f095ea7b3000000000000000000000000000000000000000000000000000000009061090190859085906024016135b8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506104e2848261147c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109d1576000546109d1906100f290339073ffffffffffffffffffffffffffffffffffffffff16611534565b565b6109e58230338463ffffffff61155116565b5050565b81518151600091908114610a0557610a056100f282855161178c565b34915060005b818114610ab4576000858281518110610a2057fe5b6020026020010151905080841015610a3f57610a3f6100f282866117a9565b610a4f848263ffffffff610df516565b9350848281518110610a5d57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610aaa573d6000803e3d6000fd5b5050600101610a0b565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610b1f57600080fd5b505af1158015610b33573d6000803e3d6000fd5b50505050505092915050565b6000806000610bf4600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631ce4c78b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610baf57600080fd5b505afa158015610bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610be791908101906133df565b3a9063ffffffff6117c616565b905060005b86518114610d4957868181518110610c0d57fe5b60200260200101516080015160001480610c3e5750868181518110610c2e57fe5b602002602001015160a001516000145b15610c4857610d41565b6000610c5a878663ffffffff610df516565b90506000610c7a898481518110610c6d57fe5b60200260200101516117f7565b610c845783610c87565b60005b905080821115610ca857610ca1828263ffffffff610df516565b9150610caf565b5050610d49565b610cb761297e565b610ce88a8581518110610cc657fe5b6020026020010151898681518110610cda57fe5b60200260200101518561186c565b60408101518151919250610d1391610d07908a9063ffffffff611bde16565b9063ffffffff611bde16565b9650610d2c816020015187611bde90919063ffffffff16565b9550888710610d3d57505050610d49565b5050505b600101610bf9565b5050935093915050565b606063cdcbed5d60e01b8383604051602401610d709291906138b2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905092915050565b600082821115610e0e57610e0e6100f260028585611bf6565b50900390565b80156107b2576001546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d90610e709084906004016138a9565b600060405180830381600087803b158015610e8a57600080fd5b505af1158015610e9e573d6000803e3d6000fd5b505060405133925083156108fc02915083906000818181858888f193505050501580156109e5573d6000803e3d6000fd5b606063450a021960e01b8383604051602401610d709291906138b2565b60008080805b86518114610ff157868181518110610f0657fe5b60200260200101516080015160001480610f375750868181518110610f2757fe5b602002602001015160a001516000145b15610f4157610fe9565b6000610f53878663ffffffff610df516565b9050610f5d61297e565b610f8e898481518110610f6c57fe5b6020026020010151888581518110610f8057fe5b60200260200101518461186c565b8051909150610fa490879063ffffffff611bde16565b9550610fbd816020015186611bde90919063ffffffff16565b9450610fd6816040015185611bde90919063ffffffff16565b9350878610610fe6575050610ff1565b50505b600101610ef2565b50611002838263ffffffff611bde16565b925050935093915050565b82516000908190815b8181146113805786818151811061102957fe5b6020026020010151608001516000148061105a575086818151811061104a57fe5b602002602001015160a001516000145b1561106457611378565b6000611076878563ffffffff610df516565b905060006110a660008a858151811061108b57fe5b602002602001015161014001516107d990919063ffffffff16565b90506000807fffffffff0000000000000000000000000000000000000000000000000000000083167fdc1600f30000000000000000000000000000000000000000000000000000000014156111c95761112160108c878151811061110657fe5b6020026020010151610140015161088990919063ffffffff16565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a08231906111769030906004016134d5565b60206040518083038186803b15801561118e57600080fd5b505afa1580156111a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111c691908101906133df565b90505b6000806111fd8d88815181106111db57fe5b60200260200101518c89815181106111ef57fe5b602002602001015188611c15565b90925090507fffffffff0000000000000000000000000000000000000000000000000000000085167fdc1600f3000000000000000000000000000000000000000000000000000000001415611310576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8616906370a08231906112a19030906004016134d5565b60206040518083038186803b1580156112b957600080fd5b505afa1580156112cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112f191908101906133df565b905061130c611306828663ffffffff610df516565b83611d4e565b9150505b61133b818e898151811061132057fe5b602002602001015161014001516109d390919063ffffffff16565b61134b8a8363ffffffff611bde16565b995061135d898263ffffffff611bde16565b98508b891061137157505050505050611380565b5050505050505b600101611016565b5084821015611396576113966100f28684611d65565b50935093915050565b60408051808201909152600481527fe69edc3e00000000000000000000000000000000000000000000000000000000602082015290565b6060632800659560e01b8484846040516024016113f593929190613640565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290505b9392505050565b600060608373ffffffffffffffffffffffffffffffffffffffff16836040516114a591906134b9565b6000604051808303816000865af19150503d80600081146114e2576040519150601f19603f3d011682016040523d82523d6000602084013e6114e7565b606091505b5091509150811561152b5780516114ff5750506109e5565b80516020141561152b576000611516826000611d82565b90508060011415611529575050506109e5565b505b6104e2816102f6565b6060631de45ad160e01b8383604051602401610d709291906134f6565b8061155b576104e2565b600061156d858263ffffffff6107d916565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167ff47261b000000000000000000000000000000000000000000000000000000000148061160057507fffffffff0000000000000000000000000000000000000000000000000000000081167fdc1600f300000000000000000000000000000000000000000000000000000000145b1561161c576116178585858563ffffffff611d8e16565b611785565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f02571792000000000000000000000000000000000000000000000000000000001415611678576116178585858563ffffffff611dd816565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fa7cb5fb70000000000000000000000000000000000000000000000000000000014156116d4576116178585858563ffffffff611ea716565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611730576116178585858563ffffffff611ffd16565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fc339d10a0000000000000000000000000000000000000000000000000000000014611785576117856100f282612091565b5050505050565b6060633ecb6ceb60e01b8383604051602401610d709291906138b2565b606063ecf40fd960e01b8383604051602401610d709291906138b2565b6000826117d557506000610829565b828202828482816117e257fe5b0414611475576114756100f260018686611bf6565b600060038261018001515111801561082957506101808201517f770501f8000000000000000000000000000000000000000000000000000000009061184390600063ffffffff6107d916565b7fffffffff00000000000000000000000000000000000000000000000000000000161492915050565b61187461297e565b61014084015160009061188d908263ffffffff6107d916565b90506000807fffffffff0000000000000000000000000000000000000000000000000000000083167fdc1600f300000000000000000000000000000000000000000000000000000000141561199b576101408701516118f390601063ffffffff61088916565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815290925073ffffffffffffffffffffffffffffffffffffffff8316906370a08231906119489030906004016134d5565b60206040518083038186803b15801561196057600080fd5b505afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061199891908101906133df565b90505b60e087015115806119bb57506119bb876101a001518861014001516120ac565b15611a09576119c861299f565b6119d3888789612259565b6020810151865260808101516040870152606081015181519192506119fe919063ffffffff610df516565b602086015250611aa5565b611a1d876101a001518861016001516120ac565b15611a945760a087015160e0880151600091611a4a91611a4490829063ffffffff611bde16565b88612294565b9050611a5461299f565b611a5f89838a612259565b9050611a7c81606001518260200151611bde90919063ffffffff16565b86528051602087015260800151604086015250611aa5565b611aa56100f2886101a001516122ca565b7fffffffff0000000000000000000000000000000000000000000000000000000083167fdc1600f3000000000000000000000000000000000000000000000000000000001415611bba576040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190611b449030906004016134d5565b60206040518083038186803b158015611b5c57600080fd5b505afa158015611b70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b9491908101906133df565b9050611bb3611ba9828463ffffffff610df516565b8660200151611d4e565b6020860152505b6020840151610140880151611bd49163ffffffff6109d316565b5050509392505050565b600082820183811015611475576114756100f2600086865b606063e946c1bb60e01b8484846040516024016113f59392919061361e565b6000808460e0015160001480611c3a5750611c3a856101a001518661016001516120ac565b15611c9c576000611c548660a00151876080015186612294565b9050611c5e61299f565b611c69878388612259565b9050611c8e8160800151610d0783606001518460200151611bde90919063ffffffff16565b90519093509150611d469050565b611cb0856101a001518661014001516120ac565b15611d35576000611ce08660a00151611cda8860e001518960800151610df590919063ffffffff16565b86612294565b9050611cea61299f565b611cf5878388612259565b9050611d1281608001518260200151611bde90919063ffffffff16565b60608201518251919550611d2c919063ffffffff610df516565b92505050611d46565b611d466100f2866101a001516122ca565b935093915050565b600081831015611d5e5781611475565b5090919050565b60606391353a0c60e01b8383604051602401610d709291906138b2565b600061147583836122e5565b6000611da185601063ffffffff61088916565b905073ffffffffffffffffffffffffffffffffffffffff8416301415611dcc5761161781848461230f565b61178581858585612347565b80600114611dec57611dec6100f28261240a565b6000611dff85601063ffffffff61088916565b90506000611e1486602463ffffffff611d8216565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd90611e6d90889088908690600401613587565b600060405180830381600087803b158015611e8757600080fd5b505af1158015611e9b573d6000803e3d6000fd5b50505050505050505050565b60006060806060611ec5600489518a6124259092919063ffffffff16565b806020019051611ed89190810190612f39565b9350935093509350600082519050606081604051908082528060200260200182016040528015611f12578160200160208202803883390190505b50905060005b828114611f6457611f4588868381518110611f2f57fe5b60200260200101516117c690919063ffffffff16565b828281518110611f5157fe5b6020908102919091010152600101611f18565b506040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690632eb2c2d690611fbf908c908c908a9087908a9060040161351d565b600060405180830381600087803b158015611fd957600080fd5b505af1158015611fed573d6000803e3d6000fd5b5050505050505050505050505050565b60608061201760048751886124259092919063ffffffff16565b80602001905161202a9190810190613254565b8051919350915060005b8181146120875761207f83828151811061204a57fe5b6020026020010151888861207a88868151811061206357fe5b60200260200101518a6117c690919063ffffffff16565b611551565b600101612034565b5050505050505050565b6060637996a27160e01b8260405160240161027291906135de565b6000806120bf848263ffffffff6107d916565b905060006120d3848263ffffffff6107d916565b90507ff47261b0000000000000000000000000000000000000000000000000000000007fdc1600f3000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000841682148061216b57507fffffffff00000000000000000000000000000000000000000000000000000000848116908216145b80156121c957507fffffffff0000000000000000000000000000000000000000000000000000000083811690831614806121c957507fffffffff00000000000000000000000000000000000000000000000000000000838116908216145b156122345760006121e188601063ffffffff61088916565b905060006121f688601063ffffffff61088916565b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149650505050505050610829565b612244878763ffffffff6124a516565b945050505050610829565b5050505092915050565b61226161299f565b61226a846117f7565b156122815761227a8484846124ca565b9050611475565b61228c84848461271e565b949350505050565b600061228c836122be6122ae82600163ffffffff610df516565b610d07888763ffffffff6117c616565b9063ffffffff61288b16565b60606331360af160e01b82604051602401610272919061360b565b60008160200183511015612306576123066100f260058551856020016113d6565b50016020015190565b6040516060907fa9059cbb000000000000000000000000000000000000000000000000000000009061090190859085906024016135b8565b6040516060907f23b872dd000000000000000000000000000000000000000000000000000000009061238190869086908690602401613587565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611785858261147c565b606063baffa47460e01b8260405160240161027291906138a9565b60608183111561243e5761243e6100f2600085856113d6565b8351821115612457576124576100f260018487516113d6565b8282036040519080825280601f01601f191660200182016040528015612484576020820181803883390190505b509050611475612493826128b5565b8461249d876128b5565b0183516128bb565b6000815183511480156114755750508051602091820120825192909101919091201490565b6124d261299f565b6124da6129ce565b604051806101800160405280866000015173ffffffffffffffffffffffffffffffffffffffff168152602001866020015173ffffffffffffffffffffffffffffffffffffffff168152602001866040015173ffffffffffffffffffffffffffffffffffffffff168152602001866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866080015181526020018660a001518152602001600081526020016000815260200186610100015181526020018661012001518152602001866101400151815260200186610160015181525090506060600073ffffffffffffffffffffffffffffffffffffffff1663b4be83d5905060e01b8286866040516024016125ed9392919061364e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600454915190925073ffffffffffffffffffffffffffffffffffffffff90911690600090606090839061269e9086906134b9565b6000604051808303816000865af19150503d80600081146126db576040519150601f19603f3d011682016040523d82523d6000602084013e6126e0565b606091505b509150915081156127125780516080146126f657fe5b8080602001905161270a91908101906133f7565b602088015286525b50505050509392505050565b61272661299f565b6040516060907f9b44d55600000000000000000000000000000000000000000000000000000000906127609087908790879060240161376e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600354915190925073ffffffffffffffffffffffffffffffffffffffff9091169060009060609083906128119086906134b9565b6000604051808303816000865af19150503d806000811461284e576040519150601f19603f3d011682016040523d82523d6000602084013e612853565b606091505b5091509150811561288057805160a01461286957fe5b8080602001905161287d919081019061338e565b94505b505050509392505050565b6000816128a1576128a16100f260038585611bf6565b60008284816128ac57fe5b04949350505050565b60200190565b60208110156128e5576001816020036101000a038019835116818551168082178652505050610539565b828214156128f257610539565b8282111561292c5760208103905080820181840181515b82851015612924578451865260209586019590940193612909565b905250610539565b60208103905080820181840183515b8186121561297557825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0928301929091019061293b565b85525050505050565b60405180606001604052806000815260200160008152602001600081525090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b803561082981613975565b600082601f830112612aa2578081fd5b8135612ab5612ab0826138e7565b6138c0565b818152915060208083019084810181840286018201871015612ad657600080fd5b60005b84811015612afe578135612aec81613975565b84529282019290820190600101612ad9565b505050505092915050565b600082601f830112612b19578081fd5b8135612b27612ab0826138e7565b8181529150602080830190840160005b8381101561224f57612b4f8760208435890101612e66565b83526020928301929190910190600101612b37565b600082601f830112612b74578081fd5b8135612b82612ab0826138e7565b818152915060208083019084810160005b84811015612afe57813587016101c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838c03011215612bd357600080fd5b612bdc816138c0565b612be88b878501612a87565b8152612bf78b60408501612a87565b86820152612c088b60608501612a87565b6040820152612c1a8b60808501612a87565b606082015260a0830135608082015260c083013560a082015260e083013560c08201526101008084013560e0830152610120808501358284015261014091508185013581840152506101608085013567ffffffffffffffff80821115612c7f57600080fd5b612c8d8f8b848a0101612e66565b84860152610180935083870135915080821115612ca957600080fd5b612cb78f8b848a0101612e66565b838601526101a0925082870135915080821115612cd357600080fd5b612ce18f8b848a0101612e66565b8486015285870135935080841115612cf857600080fd5b5050612d088d8984880101612e66565b9083015250865250509282019290820190600101612b93565b60008083601f840112612d32578182fd5b50813567ffffffffffffffff811115612d49578182fd5b6020830191508360208083028501011115612d6357600080fd5b9250929050565b600082601f830112612d7a578081fd5b8151612d88612ab0826138e7565b818152915060208083019084810181840286018201871015612da957600080fd5b60005b84811015612afe57815184529282019290820190600101612dac565b600082601f830112612dd8578081fd5b8135612de6612ab0826138e7565b818152915060208083019084810181840286018201871015612e0757600080fd5b60005b84811015612afe57813584529282019290820190600101612e0a565b60008083601f840112612e37578182fd5b50813567ffffffffffffffff811115612e4e578182fd5b602083019150836020828501011115612d6357600080fd5b600082601f830112612e76578081fd5b8135612e84612ab082613907565b9150808252836020828501011115612e9b57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612ec4578081fd5b8151612ed2612ab082613907565b9150808252836020828501011115612ee957600080fd5b612efa816020840160208601613949565b5092915050565b600060208284031215612f12578081fd5b813561147581613975565b600060208284031215612f2e578081fd5b815161147581613975565b60008060008060808587031215612f4e578283fd5b8451612f5981613975565b602086015190945067ffffffffffffffff80821115612f76578485fd5b612f8288838901612d6a565b94506040870151915080821115612f97578384fd5b612fa388838901612d6a565b93506060870151915080821115612fb8578283fd5b50612fc587828801612eb4565b91505092959194509250565b60008060008060008060008060a0898b031215612fec578586fd5b8835612ff781613975565b9750602089013561300781613975565b9650604089013567ffffffffffffffff80821115613023578788fd5b61302f8c838d01612d21565b909850965060608b0135915080821115613047578586fd5b6130538c838d01612d21565b909650945060808b013591508082111561306b578384fd5b506130788b828c01612e26565b999c989b5096995094979396929594505050565b60008060008060008060a087890312156130a4578384fd5b86356130af81613975565b955060208701356130bf81613975565b94506040870135935060608701359250608087013567ffffffffffffffff8111156130e8578283fd5b6130f489828a01612e26565b979a9699509497509295939492505050565b6000806000806080858703121561311b578182fd5b843567ffffffffffffffff80821115613132578384fd5b61313e88838901612b64565b95506020870135915080821115613153578384fd5b61315f88838901612b09565b94506040870135915080821115613174578384fd5b61318088838901612dc8565b93506060870135915080821115613195578283fd5b50612fc587828801612a92565b600080600080600060a086880312156131b9578283fd5b853567ffffffffffffffff808211156131d0578485fd5b6131dc89838a01612b64565b96506020880135955060408801359150808211156131f8578485fd5b61320489838a01612b09565b94506060880135915080821115613219578283fd5b61322589838a01612dc8565b9350608088013591508082111561323a578283fd5b5061324788828901612a92565b9150509295509295909350565b60008060408385031215613266578182fd5b825167ffffffffffffffff8082111561327d578384fd5b61328986838701612d6a565b935060209150818501518181111561329f578384fd5b85019050601f810186136132b1578283fd5b80516132bf612ab0826138e7565b81815283810190838501865b848110156132f4576132e28b888451890101612eb4565b845292860192908601906001016132cb565b5096999098509650505050505050565b60008060208385031215613316578182fd5b823567ffffffffffffffff81111561332c578283fd5b61333885828601612e26565b90969095509350505050565b600080600060408486031215613358578081fd5b833567ffffffffffffffff81111561336e578182fd5b61337a86828701612e26565b909790965060209590950135949350505050565b600060a0828403121561339f578081fd5b6133a960a06138c0565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b6000602082840312156133f0578081fd5b5051919050565b60008060408385031215613409578182fd5b505080516020909101519092909150565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845260208401935060208301825b82811015613465578151865260209586019590910190600101613447565b5093949350505050565b60008151808452613487816020860160208601613949565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082516134cb818460208701613949565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a0604083015261355660a0830186613434565b82810360608401526135688186613434565b838103608085015261357a818661346f565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b600060208252611475602083018461346f565b606081016004851061362c57fe5b938152602081019290925260409091015290565b606081016008851061362c57fe5b60006060825261366260608301865161341a565b6020850151613674608084018261341a565b50604085015161368760a084018261341a565b50606085015161369a60c084018261341a565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e088015192506101408381870152828901519350610160925083838701528189015193506101809150838287015280890151935050806101a08601525061370d6101e085018361346f565b8188015192507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0858203016101c0860152613748818461346f565b9150508560208501528381036040850152613763818661346f565b979650505050505050565b60006060825261378260608301865161341a565b6020850151613794608084018261341a565b5060408501516137a760a084018261341a565b5060608501516137ba60c084018261341a565b50608085015160e083015260a0850151610100818185015260c08701519150610120828186015260e0880151925061014083818701528289015193506101609250838387015281890151935061018091508382870152808901519350506101c06101a0818188015261383061022088018661346f565b848b015195507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0945084888203018389015261386c818761346f565b925050828a0151945083878303016101e088015261388a828661346f565b9250808a0151945050508185820301610200860152613748818461346f565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156138df57600080fd5b604052919050565b600067ffffffffffffffff8211156138fd578081fd5b5060209081020190565b600067ffffffffffffffff82111561391d578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b8381101561396457818101518382015260200161394c565b838111156104e25750506000910152565b73ffffffffffffffffffffffffffffffffffffffff811681146107b257600080fdfea365627a7a7231582044b5b700e71da9b34ea681113c5c2d7dc51a60db3338ae1b4863b61744fd81b86c6578706572696d656e74616cf564736f6c63430005110040" } } }, "compiler": { "name": "solc", - "version": "soljson-v0.5.16+commit.9c3226ce.js", + "version": "soljson-v0.5.17+commit.d19bba13.js", "settings": { "optimizer": { "enabled": true, diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index abd74491da..0741c46114 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -9,6 +9,10 @@ { "note": "Added wrapper for MaximumGasPrice", "pr": 2511 + }, + { + "note": "Added `Forwarder.marketSellAmountWithEth`", + "pr": 2521 } ] }, diff --git a/packages/contract-wrappers/src/generated-wrappers/forwarder.ts b/packages/contract-wrappers/src/generated-wrappers/forwarder.ts index 31b4e175a1..0816971340 100644 --- a/packages/contract-wrappers/src/generated-wrappers/forwarder.ts +++ b/packages/contract-wrappers/src/generated-wrappers/forwarder.ts @@ -392,6 +392,103 @@ export class ForwarderContract extends BaseContract { stateMutability: 'payable', type: 'function', }, + { + constant: false, + 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: 'ethSellAmount', + type: 'uint256', + }, + { + name: 'signatures', + type: 'bytes[]', + }, + { + name: 'ethFeeAmounts', + type: 'uint256[]', + }, + { + name: 'feeRecipients', + type: 'address[]', + }, + ], + name: 'marketSellAmountWithEth', + outputs: [ + { + name: 'wethSpentAmount', + type: 'uint256', + }, + { + name: 'makerAssetAcquiredAmount', + type: 'uint256', + }, + ], + payable: true, + stateMutability: 'payable', + type: 'function', + }, { constant: false, inputs: [ @@ -891,6 +988,100 @@ export class ForwarderContract extends BaseContract { }, }; } + /** + * Purchases as much of orders' makerAssets as possible by selling the specified amount of ETH + * accounting for order and forwarder fees. This functions throws if ethSellAmount was not reached. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param ethSellAmount Desired amount of ETH to sell. + * @param signatures Proofs that orders have been created by makers. + * @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to + * corresponding feeRecipients. + * @param feeRecipients Addresses that will receive ETH when orders are filled. + * @returns wethSpentAmount Amount of WETH spent on the given set of orders.makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders. + */ + public marketSellAmountWithEth( + 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; + }>, + ethSellAmount: BigNumber, + signatures: string[], + ethFeeAmounts: BigNumber[], + feeRecipients: string[], + ): ContractTxFunctionObj<[BigNumber, BigNumber]> { + const self = (this as any) as ForwarderContract; + assert.isArray('orders', orders); + assert.isBigNumber('ethSellAmount', ethSellAmount); + assert.isArray('signatures', signatures); + assert.isArray('ethFeeAmounts', ethFeeAmounts); + assert.isArray('feeRecipients', feeRecipients); + const functionSignature = + 'marketSellAmountWithEth((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],uint256,bytes[],uint256[],address[])'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { ...txData, data: this.getABIEncodedTransactionData() }, + this.estimateGasAsync.bind(this), + ); + if (opts.shouldValidate !== false) { + await this.callAsync(txDataWithDefaults); + } + return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + }, + awaitTransactionSuccessAsync( + txData?: Partial, + opts: AwaitTransactionSuccessOpts = { shouldValidate: true }, + ): PromiseWithTransactionHash { + return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts); + }, + async estimateGasAsync(txData?: Partial | undefined): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: this.getABIEncodedTransactionData(), + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + 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, + ethSellAmount, + signatures, + ethFeeAmounts, + feeRecipients, + ]); + }, + }; + } /** * Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent * as possible, accounting for order and forwarder fees. diff --git a/packages/utils/src/revert_errors/exchange-forwarder/revert_errors.ts b/packages/utils/src/revert_errors/exchange-forwarder/revert_errors.ts index 03dc953de8..0b078269ea 100644 --- a/packages/utils/src/revert_errors/exchange-forwarder/revert_errors.ts +++ b/packages/utils/src/revert_errors/exchange-forwarder/revert_errors.ts @@ -22,6 +22,19 @@ export class CompleteBuyFailedError extends RevertError { } } +export class CompleteSellFailedError extends RevertError { + constructor( + expectedAssetSellAmount?: BigNumber | number | string, + actualAssetSellAmount?: BigNumber | number | string, + ) { + super( + 'CompleteSellFailedError', + 'CompleteSellFailedError(uint256 expectedAssetSellAmount, uint256 actualAssetSellAmount)', + { expectedAssetSellAmount, actualAssetSellAmount }, + ); + } +} + export class UnsupportedFeeError extends RevertError { constructor(takerFeeAssetData?: string) { super('UnsupportedFeeError', 'UnsupportedFeeError(bytes takerFeeAssetData)', { takerFeeAssetData }); @@ -46,6 +59,7 @@ export class MsgValueCannotEqualZeroError extends RevertError { const types = [ UnregisteredAssetProxyError, CompleteBuyFailedError, + CompleteSellFailedError, UnsupportedFeeError, OverspentWethError, MsgValueCannotEqualZeroError,