From e21e353658c71c3a794aa43c3a1cdf2d1185c9e5 Mon Sep 17 00:00:00 2001 From: xianny Date: Fri, 19 Apr 2019 13:51:08 -0700 Subject: [PATCH 01/53] wip first pass at coordinator wrapper --- packages/contract-wrappers/package.json | 3 + .../src/contract_wrappers.ts | 16 + .../contract_wrappers/coordinator_wrapper.ts | 548 ++++++++++++++++++ packages/contract-wrappers/src/index.ts | 1 + packages/contract-wrappers/src/types.ts | 5 + .../test/coordinator_wrapper_test.ts | 346 +++++++++++ 6 files changed, 919 insertions(+) create mode 100644 packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts create mode 100644 packages/contract-wrappers/test/coordinator_wrapper_test.ts diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 83f0869e48..fa54ce1b06 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -39,6 +39,7 @@ }, "devDependencies": { "@0x/contracts-test-utils": "^3.1.2", + "@0x/coordinator-server": "^0.0.6", "@0x/dev-utils": "^2.2.1", "@0x/fill-scenarios": "^3.0.5", "@0x/migrations": "^4.1.1", @@ -78,6 +79,7 @@ "@0x/typescript-typings": "^4.2.2", "@0x/utils": "^4.3.1", "@0x/web3-wrapper": "^6.0.5", + "@types/supertest": "^2.0.7", "ethereum-types": "^2.1.2", "ethereumjs-abi": "0.6.5", "ethereumjs-blockstream": "6.0.0", @@ -85,6 +87,7 @@ "ethers": "~4.0.4", "js-sha3": "^0.7.0", "lodash": "^4.17.11", + "supertest": "^4.0.2", "uuid": "^3.3.2" }, "publishConfig": { diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts index c8731551be..8f7d838af9 100644 --- a/packages/contract-wrappers/src/contract_wrappers.ts +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -1,4 +1,5 @@ import { + Coordinator, DutchAuction, ERC20Proxy, ERC20Token, @@ -14,6 +15,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; import { SupportedProvider } from 'ethereum-types'; import * as _ from 'lodash'; +import { CoordinatorWrapper } from './contract_wrappers/coordinator_wrapper'; import { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper'; import { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper'; import { ERC20TokenWrapper } from './contract_wrappers/erc20_token_wrapper'; @@ -73,6 +75,11 @@ export class ContractWrappers { */ public dutchAuction: DutchAuctionWrapper; + /** + * An instance of the CoordinatorWrapper class containing methods for interacting with any Coordinator smart contract. + */ + public coordinator: CoordinatorWrapper; + private readonly _web3Wrapper: Web3Wrapper; /** * Instantiates a new ContractWrappers instance. @@ -88,6 +95,7 @@ export class ContractWrappers { }; this._web3Wrapper = new Web3Wrapper(supportedProvider, txDefaults); const artifactsArray = [ + Coordinator, DutchAuction, ERC20Proxy, ERC20Token, @@ -155,6 +163,14 @@ export class ContractWrappers { config.networkId, contractAddresses.dutchAuction, ); + this.coordinator = new CoordinatorWrapper( + this._web3Wrapper, + config.networkId, + contractAddresses.coordinator, + contractAddresses.exchange, + contractAddresses.coordinatorRegistry, + blockPollingIntervalMs, + ); } /** * Unsubscribes from all subscriptions for all contracts. diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts new file mode 100644 index 0000000000..881860c085 --- /dev/null +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -0,0 +1,548 @@ +import { + CoordinatorContract, + CoordinatorRegistryContract, + ExchangeContract, +} from '@0x/abi-gen-wrappers'; +import { Coordinator, CoordinatorRegistry, Exchange } from '@0x/contract-artifacts'; +import { schemas } from '@0x/json-schemas'; +import { + generatePseudoRandomSalt, + signatureUtils, + transactionHashUtils, +} from '@0x/order-utils'; +import { Order, SignedOrder, ZeroExTransaction } from '@0x/types'; +import { BigNumber, fetchAsync } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { ContractAbi } from 'ethereum-types'; +import * as http from 'http'; +import * as request from 'supertest'; + +import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; +import { txOptsSchema } from '../schemas/tx_opts_schema'; +import { + CoordinatorServerResponse, + OrderTransactionOpts, +} from '../types'; +import { assert } from '../utils/assert'; +import { _getDefaultContractAddresses } from '../utils/contract_addresses'; +import { decorators } from '../utils/decorators'; +import { TransactionEncoder } from '../utils/transaction_encoder'; + +import { ContractWrapper } from './contract_wrapper'; + +const HTTP_OK = 200; + +/** + * This class includes all the functionality related to calling methods, sending transactions and subscribing to + * events of the 0x V2 Coordinator smart contract. + */ +export class CoordinatorWrapper extends ContractWrapper { + public abi: ContractAbi = Coordinator.compilerOutput.abi; + public networkId: number; + public address: string; + public exchangeAddress: string; + public registryAddress: string; + private _contractInstance: CoordinatorContract; + private _registryInstance: CoordinatorRegistryContract; + private _exchangeInstance: ExchangeContract; + private _transactionEncoder: TransactionEncoder; + + /** + * Instantiate ExchangeWrapper + * @param web3Wrapper Web3Wrapper instance to use. + * @param networkId Desired networkId. + * @param address The address of the Coordinator contract. If undefined, will + * default to the known address corresponding to the networkId. + * @param registryAddress The address of the Coordinator contract. If undefined, will + * default to the known address corresponding to the networkId. + * @param zrxTokenAddress The address of the ZRXToken contract. If + * undefined, will default to the known address corresponding to the + * networkId. + * @param blockPollingIntervalMs The block polling interval to use for active subscriptions. + */ + constructor( + web3Wrapper: Web3Wrapper, + networkId: number, + address?: string, + exchangeAddress?: string, + registryAddress?: string, + blockPollingIntervalMs?: number, + ) { + super(web3Wrapper, networkId, blockPollingIntervalMs); + this.networkId = networkId; + this.address = address === undefined ? _getDefaultContractAddresses(networkId).coordinator : address; + this.exchangeAddress = exchangeAddress === undefined + ? _getDefaultContractAddresses(networkId).coordinator + : exchangeAddress; + this.registryAddress = registryAddress === undefined + ? _getDefaultContractAddresses(networkId).coordinatorRegistry + : registryAddress; + + this._contractInstance = new CoordinatorContract( + this.abi, + this.address, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + this._registryInstance = new CoordinatorRegistryContract( + CoordinatorRegistry.compilerOutput.abi, + this.registryAddress, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + this._exchangeInstance = new ExchangeContract( + Exchange.compilerOutput.abi, + this.exchangeAddress, + this._web3Wrapper.getProvider(), + this._web3Wrapper.getContractDefaults(), + ); + + this._transactionEncoder = new TransactionEncoder(this._exchangeInstance); + } + + /** + * Fills a signed order with an amount denominated in baseUnits of the taker asset. + * @param signedOrder An object that conforms to the SignedOrder interface. + * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. + * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async fillOrderAsync( + signedOrder: SignedOrder, + takerAssetFillAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); + const data = this._transactionEncoder.fillOrderTx(signedOrder, takerAssetFillAmount); + return this._handleFillAsync(data, takerAddress, signedOrder.feeRecipientAddress, orderTransactionOpts); + } + + /** + * No-throw version of fillOrderAsync. This version will not throw if the fill fails. This allows the caller to save gas at the expense of not knowing the reason the fill failed. + * @param signedOrder An object that conforms to the SignedOrder interface. + * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. + * @param takerAddress The user Ethereum address who would like to fill this order. + * Must be available via the supplied Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async fillOrderNoThrowAsync( + signedOrder: SignedOrder, + takerAssetFillAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); + const data = this._transactionEncoder.fillOrderNoThrowTx(signedOrder, takerAssetFillAmount); + return this._handleFillAsync(data, takerAddress, signedOrder.feeRecipientAddress, orderTransactionOpts); + } + + /** + * Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled, + * the fill order is abandoned. + * @param signedOrder An object that conforms to the SignedOrder interface. + * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. + * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async fillOrKillOrderAsync( + signedOrder: SignedOrder, + takerAssetFillAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); + assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); + const data = this._transactionEncoder.fillOrKillOrderTx(signedOrder, takerAssetFillAmount); + return this._handleFillAsync(data, takerAddress, signedOrder.feeRecipientAddress, orderTransactionOpts); + } + + /** + * Batch version of fillOrderAsync. Executes multiple fills atomically in a single transaction. + * @param signedOrders An array of signed orders to fill. + * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. + * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async batchFillOrdersAsync( + signedOrders: SignedOrder[], + takerAssetFillAmounts: BigNumber[], + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + for (const takerAssetFillAmount of takerAssetFillAmounts) { + assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); + } + const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + const data = this._transactionEncoder.batchFillOrdersTx(signedOrders, takerAssetFillAmounts); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * No throw version of batchFillOrdersAsync + * @param signedOrders An array of signed orders to fill. + * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. + * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async batchFillOrdersNoThrowAsync( + signedOrders: SignedOrder[], + takerAssetFillAmounts: BigNumber[], + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + for (const takerAssetFillAmount of takerAssetFillAmounts) { + assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); + } + const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + const data = this._transactionEncoder.batchFillOrdersNoThrowTx(signedOrders, takerAssetFillAmounts); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * Batch version of fillOrKillOrderAsync. Executes multiple fills atomically in a single transaction. + * @param signedOrders An array of signed orders to fill. + * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. + * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async batchFillOrKillOrdersAsync( + signedOrders: SignedOrder[], + takerAssetFillAmounts: BigNumber[], + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + for (const takerAssetFillAmount of takerAssetFillAmounts) { + assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); + } + const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + const data = this._transactionEncoder.batchFillOrKillOrdersTx(signedOrders, takerAssetFillAmounts); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. + * @param signedOrders An array of signed orders to fill. + * @param makerAssetFillAmount Maker asset fill amount. + * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async marketBuyOrdersAsync( + signedOrders: SignedOrder[], + makerAssetFillAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); + const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + const data = this._transactionEncoder.marketBuyOrdersTx(signedOrders, makerAssetFillAmount); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. + * @param signedOrders An array of signed orders to fill. + * @param takerAssetFillAmount Taker asset fill amount. + * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async marketSellOrdersAsync( + signedOrders: SignedOrder[], + takerAssetFillAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); + const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + const data = this._transactionEncoder.marketSellOrdersTx(signedOrders, takerAssetFillAmount); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * No throw version of marketBuyOrdersAsync + * @param signedOrders An array of signed orders to fill. + * @param makerAssetFillAmount Maker asset fill amount. + * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async marketBuyOrdersNoThrowAsync( + signedOrders: SignedOrder[], + makerAssetFillAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); + const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + const data = this._transactionEncoder.marketBuyOrdersNoThrowTx(signedOrders, makerAssetFillAmount); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * No throw version of marketSellOrdersAsync + * @param signedOrders An array of signed orders to fill. + * @param takerAssetFillAmount Taker asset fill amount. + * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied + * Provider provided at instantiation. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async marketSellOrdersNoThrowAsync( + signedOrders: SignedOrder[], + takerAssetFillAmount: BigNumber, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); + assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); + const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + const data = this._transactionEncoder.marketSellOrdersNoThrowTx(signedOrders, takerAssetFillAmount); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * Match two complementary orders that have a profitable spread. + * Each order is filled at their respective price point. However, the calculations are carried out as though + * the orders are both being filled at the right order's price point. + * The profit made by the left order goes to the taker (whoever matched the two orders). + * @param leftSignedOrder First order to match. + * @param rightSignedOrder Second order to match. + * @param takerAddress The address that sends the transaction and gets the spread. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async matchOrdersAsync( + leftSignedOrder: SignedOrder, + rightSignedOrder: SignedOrder, + takerAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('leftSignedOrder', leftSignedOrder, schemas.signedOrderSchema); + assert.doesConformToSchema('rightSignedOrder', rightSignedOrder, schemas.signedOrderSchema); + const feeRecipientAddress = getFeeRecipientOrThrow([leftSignedOrder, rightSignedOrder]); + const data = this._transactionEncoder.matchOrdersTx(leftSignedOrder, rightSignedOrder); + return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * Cancel a given order. + * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async cancelOrderAsync( + order: Order | SignedOrder, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('order', order, schemas.orderSchema); + const data = this._transactionEncoder.cancelOrderTx(order); + return this._handleFillAsync(data, order.makerAddress, order.feeRecipientAddress, orderTransactionOpts); // todo: is this the right taker address? + } + + /** + * Batch version of cancelOrderAsync. Executes multiple cancels atomically in a single transaction. + * @param orders An array of orders to cancel. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async batchCancelOrdersAsync( + orders: SignedOrder[], + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.doesConformToSchema('orders', orders, schemas.ordersSchema); + const makerAddresses = orders.map(o => o.makerAddress); + const makerAddress = makerAddresses[0]; + const feeRecipientAddress = getFeeRecipientOrThrow(orders); + const data = this._transactionEncoder.batchCancelOrdersTx(orders); + return this._handleFillAsync(data, makerAddress, feeRecipientAddress, orderTransactionOpts); + } + + /** + * Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch + * and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). + * @param targetOrderEpoch Target order epoch. + * @param senderAddress Address that should send the transaction. + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async cancelOrdersUpToAsync( + targetOrderEpoch: BigNumber, + senderAddress: string, + coordinatorOperatorAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); + const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); + return this._handleFillAsync(data, senderAddress, coordinatorOperatorAddress, orderTransactionOpts); + } + + /** + * Executes a 0x transaction. Transaction messages exist for the purpose of calling methods on the Exchange contract + * in the context of another address (see [ZEIP18](https://github.com/0xProject/ZEIPs/issues/18)). + * This is especially useful for implementing filter contracts. + * @param salt Salt + * @param signerAddress Signer address + * @param data Transaction data + * @param signature Signature + * @param takerAddress Sender address + * @param feeRecipientAddress Coordinator operator address registered in CoordinatorRegistryContract + * @param orderTransactionOpts Optional arguments this method accepts. + * @return Transaction hash. + */ + @decorators.asyncZeroExErrorHandler + public async executeTransactionWithApprovalAsync( + salt: BigNumber, + signerAddress: string, + data: string, + signature: string, + takerAddress: string, + feeRecipientAddress: string, + orderTransactionOpts: OrderTransactionOpts, + ): Promise { + assert.isBigNumber('salt', salt); + assert.isETHAddressHex('signerAddress', signerAddress); + assert.isHexString('data', data); + assert.isHexString('signature', signature); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + + const coordinatorOperatorEndpoint = await this._registryInstance.getCoordinatorEndpoint.callAsync( + feeRecipientAddress, + ); + if (coordinatorOperatorEndpoint === undefined) { + throw new Error( + `Could not find endpoint for coordinator operator with { coordinatorAddress: ${ + this.address + }, registryAddress: ${this.registryAddress}, operatorAddress: ${feeRecipientAddress}}`, + ); + } + + const txOrigin = takerAddress; + const zeroExTransaction = { + salt, + signerAddress, + data, + }; + + const requestPayload = { + signedTransaction: { + ...zeroExTransaction, + signature, + verifyingContractAddress: this.exchangeAddress, + }, + txOrigin, + }; + const response = await fetchAsync( + `${coordinatorOperatorEndpoint}/v1/request_transaction?networkId=${this.networkId}`, + { + body: JSON.stringify(requestPayload), + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }, + ); + + if (response.status !== HTTP_OK) { + throw new Error(``); // todo + } + + const { signatures, expirationTimeSeconds } = (await response.json()) as CoordinatorServerResponse; + + console.log(`signatures, expiration: ${JSON.stringify(signatures)}, ${JSON.stringify(expirationTimeSeconds)}`); + return this._contractInstance.executeTransaction.sendTransactionAsync( + zeroExTransaction, + txOrigin, + signature, + [expirationTimeSeconds], + signatures, + { + from: txOrigin, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, + }, + ); + } + + private async _handleFillAsync( + data: string, + takerAddress: string, + feeRecipientAddress: string, + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + ): Promise { + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + const normalizedTakerAddress = takerAddress.toLowerCase(); + + const transaction: ZeroExTransaction = { + salt: generatePseudoRandomSalt(), + signerAddress: normalizedTakerAddress, + data, + verifyingContractAddress: this.exchangeAddress, + }; + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + const signature = await signatureUtils.ecSignHashAsync( + this._web3Wrapper.getProvider(), + transactionHash, + transaction.signerAddress, + ); + + return this.executeTransactionWithApprovalAsync( + transaction.salt, + normalizedTakerAddress, + data, + signature, + normalizedTakerAddress, + feeRecipientAddress, + orderTransactionOpts, + ); + } +} // tslint:disable:max-file-line-count + +function getFeeRecipientOrThrow(orders: Array): string { + const uniqueFeeRecipients = new Set(orders.map(o => o.feeRecipientAddress)); + if (uniqueFeeRecipients.size > 1) { + throw new Error(`All orders in a batch must have the same feeRecipientAddress (a valid coordinator operator address)`); + } + return orders[0].feeRecipientAddress; +} diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 9a1579104f..66c0b34030 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -26,6 +26,7 @@ export { } from '@0x/abi-gen-wrappers'; export { ContractWrappers } from './contract_wrappers'; +export { CoordinatorWrapper } from './contract_wrappers/coordinator_wrapper'; export { ERC20TokenWrapper } from './contract_wrappers/erc20_token_wrapper'; export { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper'; export { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper'; diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 624b9ac301..c3cee1be90 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -225,3 +225,8 @@ export interface DutchAuctionData { beginTimeSeconds: BigNumber; beginAmount: BigNumber; } + +export interface CoordinatorServerResponse { + signatures: string[]; + expirationTimeSeconds: BigNumber; +} diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts new file mode 100644 index 0000000000..6cae0a4c9d --- /dev/null +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -0,0 +1,346 @@ +import { CoordinatorRegistryContract } from '@0x/abi-gen-wrappers'; +import { CoordinatorRegistry } from '@0x/contract-artifacts'; +import { constants } from '@0x/contracts-test-utils'; +import { getAppAsync } from '@0x/coordinator-server'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { FillScenarios } from '@0x/fill-scenarios'; +import { assetDataUtils } from '@0x/order-utils'; +import { SignedOrder } from '@0x/types'; +import { BigNumber, fetchAsync } from '@0x/utils'; +import * as chai from 'chai'; +import * as http from 'http'; +import 'mocha'; + +import { ContractWrappers, OrderStatus } from '../src'; + +import { chaiSetup } from './utils/chai_setup'; +import { migrateOnceAsync } from './utils/migrate'; +import { tokenUtils } from './utils/token_utils'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); +const coordinatorEndpoint = 'http://localhost:3000'; + +// tslint:disable:custom-no-magic-numbers +describe.only('CoordinatorWrapper', () => { + const fillableAmount = new BigNumber(5); + const takerTokenFillAmount = new BigNumber(5); + let app: http.Server; + let contractWrappers: ContractWrappers; + let fillScenarios: FillScenarios; + let exchangeContractAddress: string; + let zrxTokenAddress: string; + let userAddresses: string[]; + let makerAddress: string; + let takerAddress: string; + let feeRecipientAddress: string; + let anotherFeeRecipientAddress: string; + let makerTokenAddress: string; + let takerTokenAddress: string; + let makerAssetData: string; + let takerAssetData: string; + let txHash: string; + let signedOrder: SignedOrder; + let anotherSignedOrder: SignedOrder; + let signedOrderWithoutFeeRecipient: SignedOrder; + let coordinatorRegistryInstance: CoordinatorRegistryContract; + before(async () => { + const contractAddresses = await migrateOnceAsync(); + await blockchainLifecycle.startAsync(); + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + contractAddresses, + blockPollingIntervalMs: 10, + }; + contractWrappers = new ContractWrappers(provider, config); + exchangeContractAddress = contractWrappers.exchange.address; + userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress; + fillScenarios = new FillScenarios( + provider, + userAddresses, + zrxTokenAddress, + exchangeContractAddress, + contractWrappers.erc20Proxy.address, + contractWrappers.erc721Proxy.address, + ); + [, makerAddress, takerAddress, feeRecipientAddress, anotherFeeRecipientAddress] = userAddresses.slice(0, 5); + [makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); + takerTokenAddress = contractWrappers.forwarder.etherTokenAddress; + [makerAssetData, takerAssetData] = [ + assetDataUtils.encodeERC20AssetData(makerTokenAddress), + assetDataUtils.encodeERC20AssetData(takerTokenAddress), + ]; + signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + constants.NULL_ADDRESS, + fillableAmount, + feeRecipientAddress, + ); + anotherSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + constants.NULL_ADDRESS, + fillableAmount, + feeRecipientAddress, + ); + signedOrderWithoutFeeRecipient = await fillScenarios.createFillableSignedOrderAsync( + makerAssetData, + takerAssetData, + makerAddress, + constants.NULL_ADDRESS, + fillableAmount, + ); + + // set up mock coordinator server + const coordinatorServerConfigs = { + HTTP_PORT: 3000, + NETWORK_ID_TO_SETTINGS: { + 50: { + FEE_RECIPIENTS: [ + { + ADDRESS: feeRecipientAddress, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddress)].toString('hex'), + }, + { + ADDRESS: anotherFeeRecipientAddress, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(anotherFeeRecipientAddress)].toString('hex'), + }, + ], + // Ethereum RPC url, only used in the default instantiation in server.js of 0x-coordinator-server + // Not used here when instantiating with the imported app + RPC_URL: 'http://ignore', + }, + }, + // Optional selective delay on fill requests + SELECTIVE_DELAY_MS: 0, + EXPIRATION_DURATION_SECONDS: 60, // 1 minute + }; + app = await getAppAsync( + { + [config.networkId]: provider, + }, + coordinatorServerConfigs, + ); + + await app.listen(coordinatorServerConfigs.HTTP_PORT, () => { // tslint:disable-line:await-promise + console.log(`Coordinator SERVER API (HTTP) listening on port ${coordinatorServerConfigs.HTTP_PORT}!`); // tslint:disable-line:no-console + }); + + // setup coordinator registry + coordinatorRegistryInstance = new CoordinatorRegistryContract( + CoordinatorRegistry.compilerOutput.abi, + contractAddresses.coordinatorRegistry, + provider, + {gas: 6000000}); + + await web3Wrapper.awaitTransactionSuccessAsync( + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync( + coordinatorEndpoint, + { from: feeRecipientAddress }, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('test setup', () => { + it('should have coordinator registry which returns an endpoint', async () => { + const recordedCoordinatorEndpoint = await coordinatorRegistryInstance.getCoordinatorEndpoint.callAsync( + feeRecipientAddress, + ); + expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); + }); + it('should have coordinator server endpoint which responds to pings', async () => { + const result = await fetchAsync(`${coordinatorEndpoint}/v1/ping`); + expect(result.status).to.be.equal(200); + expect(await result.text()).to.be.equal('pong'); + }); + }); + describe('fill order(s)', () => { + describe('#fillOrderAsync', () => { + it('should fill a valid order', async () => { + txHash = await contractWrappers.coordinator.fillOrderAsync( + signedOrder, + takerTokenFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#fillOrderNoThrowAsync', () => { + it('should fill a valid order', async () => { + txHash = await contractWrappers.coordinator.fillOrderNoThrowAsync( + signedOrder, + takerTokenFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); + }); + }); + describe('#fillOrKillOrderAsync', () => { + it('should fill or kill a valid order', async () => { + txHash = await contractWrappers.coordinator.fillOrKillOrderAsync( + signedOrder, + takerTokenFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#batchFillOrdersAsync', () => { + it('should fill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.coordinator.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#marketBuyOrdersAsync', () => { + it('should maker buy', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const makerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.coordinator.marketBuyOrdersAsync( + signedOrders, + makerAssetFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#marketBuyOrdersNoThrowAsync', () => { + it('should no throw maker buy', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const makerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.coordinator.marketBuyOrdersNoThrowAsync( + signedOrders, + makerAssetFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); + }); + }); + describe('#marketSellOrdersAsync', () => { + it('should maker sell', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.coordinator.marketSellOrdersAsync( + signedOrders, + takerAssetFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#marketSellOrdersNoThrowAsync', () => { + it('should no throw maker sell', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmount = takerTokenFillAmount; + txHash = await contractWrappers.coordinator.marketSellOrdersNoThrowAsync( + signedOrders, + takerAssetFillAmount, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); + }); + }); + describe('#batchFillOrdersNoThrowAsync', () => { + it('should fill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.coordinator.batchFillOrdersNoThrowAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + let orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); + orderInfo = await contractWrappers.exchange.getOrderInfoAsync(anotherSignedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); + }); + }); + describe('#batchFillOrKillOrdersAsync', () => { + it('should fill or kill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.coordinator.batchFillOrKillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#matchOrdersAsync', () => { + it('should match two valid ordersr', async () => { + const matchingSignedOrder = await fillScenarios.createFillableSignedOrderAsync( + takerAssetData, + makerAssetData, + makerAddress, + takerAddress, + fillableAmount, + ); + txHash = await contractWrappers.coordinator.matchOrdersAsync( + signedOrder, + matchingSignedOrder, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + }); + // describe('cancel order(s)', () => { + // describe('#cancelOrderAsync', () => { + // it('should cancel a valid order', async () => { + // txHash = await contractWrappers.coordinator.cancelOrderAsync(signedOrder); + // await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + // }); + // }); + // describe('#batchCancelOrdersAsync', () => { + // it('should cancel a batch of valid orders', async () => { + // const orders = [signedOrder, anotherSignedOrder]; + // txHash = await contractWrappers.coordinator.batchCancelOrdersAsync(orders); + // await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + // }); + // }); + // describe('#cancelOrdersUpTo/getOrderEpochAsync', () => { + // it('should cancel orders up to target order epoch', async () => { + // const targetOrderEpoch = new BigNumber(42); + // txHash = await contractWrappers.coordinator.cancelOrdersUpToAsync(targetOrderEpoch, makerAddress); + // await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + // const orderEpoch = await contractWrappers.coordinator.getOrderEpochAsync( + // makerAddress, + // constants.NULL_ADDRESS, + // ); + // expect(orderEpoch).to.be.bignumber.equal(targetOrderEpoch.plus(1)); + // }); + // }); + // }); +}); From 0dfa3bad982b31dc30e9f18f2488ed84bc6a924a Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 25 Apr 2019 20:46:24 -0700 Subject: [PATCH 02/53] implement cancels, helper methods, and more unit tests --- .../src/contract_wrappers.ts | 1 - .../contract_wrappers/coordinator_wrapper.ts | 373 +++++++++----- packages/contract-wrappers/src/types.ts | 14 +- .../test/coordinator_wrapper_test.ts | 155 +++--- yarn.lock | 484 +++++++++++++++++- 5 files changed, 809 insertions(+), 218 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts index 8f7d838af9..c375d32192 100644 --- a/packages/contract-wrappers/src/contract_wrappers.ts +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -169,7 +169,6 @@ export class ContractWrappers { contractAddresses.coordinator, contractAddresses.exchange, contractAddresses.coordinatorRegistry, - blockPollingIntervalMs, ); } /** diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 881860c085..08ba7fe446 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -1,26 +1,17 @@ -import { - CoordinatorContract, - CoordinatorRegistryContract, - ExchangeContract, -} from '@0x/abi-gen-wrappers'; +import { CoordinatorContract, CoordinatorRegistryContract, ExchangeContract } from '@0x/abi-gen-wrappers'; import { Coordinator, CoordinatorRegistry, Exchange } from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; -import { - generatePseudoRandomSalt, - signatureUtils, - transactionHashUtils, -} from '@0x/order-utils'; -import { Order, SignedOrder, ZeroExTransaction } from '@0x/types'; +import { generatePseudoRandomSalt, signatureUtils, transactionHashUtils } from '@0x/order-utils'; +import { Order, SignedOrder, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; import { BigNumber, fetchAsync } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { ContractAbi } from 'ethereum-types'; -import * as http from 'http'; -import * as request from 'supertest'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; import { - CoordinatorServerResponse, + CoordinatorServerApprovalResponse, + CoordinatorServerCancellationResponse, OrderTransactionOpts, } from '../types'; import { assert } from '../utils/assert'; @@ -33,8 +24,8 @@ import { ContractWrapper } from './contract_wrapper'; const HTTP_OK = 200; /** - * This class includes all the functionality related to calling methods, sending transactions and subscribing to - * events of the 0x V2 Coordinator smart contract. + * This class includes all the functionality related to filling or cancelling orders through + * the 0x V2 Coordinator smart contract. */ export class CoordinatorWrapper extends ContractWrapper { public abi: ContractAbi = Coordinator.compilerOutput.abi; @@ -42,23 +33,19 @@ export class CoordinatorWrapper extends ContractWrapper { public address: string; public exchangeAddress: string; public registryAddress: string; - private _contractInstance: CoordinatorContract; - private _registryInstance: CoordinatorRegistryContract; - private _exchangeInstance: ExchangeContract; - private _transactionEncoder: TransactionEncoder; + private readonly _contractInstance: CoordinatorContract; + private readonly _registryInstance: CoordinatorRegistryContract; + private readonly _exchangeInstance: ExchangeContract; + private readonly _transactionEncoder: TransactionEncoder; /** - * Instantiate ExchangeWrapper + * Instantiate CoordinatorWrapper * @param web3Wrapper Web3Wrapper instance to use. * @param networkId Desired networkId. * @param address The address of the Coordinator contract. If undefined, will * default to the known address corresponding to the networkId. - * @param registryAddress The address of the Coordinator contract. If undefined, will + * @param registryAddress The address of the CoordinatorRegistry contract. If undefined, will * default to the known address corresponding to the networkId. - * @param zrxTokenAddress The address of the ZRXToken contract. If - * undefined, will default to the known address corresponding to the - * networkId. - * @param blockPollingIntervalMs The block polling interval to use for active subscriptions. */ constructor( web3Wrapper: Web3Wrapper, @@ -66,17 +53,16 @@ export class CoordinatorWrapper extends ContractWrapper { address?: string, exchangeAddress?: string, registryAddress?: string, - blockPollingIntervalMs?: number, ) { - super(web3Wrapper, networkId, blockPollingIntervalMs); + super(web3Wrapper, networkId); this.networkId = networkId; this.address = address === undefined ? _getDefaultContractAddresses(networkId).coordinator : address; - this.exchangeAddress = exchangeAddress === undefined - ? _getDefaultContractAddresses(networkId).coordinator - : exchangeAddress; - this.registryAddress = registryAddress === undefined - ? _getDefaultContractAddresses(networkId).coordinatorRegistry - : registryAddress; + this.exchangeAddress = + exchangeAddress === undefined ? _getDefaultContractAddresses(networkId).coordinator : exchangeAddress; + this.registryAddress = + registryAddress === undefined + ? _getDefaultContractAddresses(networkId).coordinatorRegistry + : registryAddress; this._contractInstance = new CoordinatorContract( this.abi, @@ -354,47 +340,119 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('leftSignedOrder', leftSignedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('rightSignedOrder', rightSignedOrder, schemas.signedOrderSchema); - const feeRecipientAddress = getFeeRecipientOrThrow([leftSignedOrder, rightSignedOrder]); + const data = this._transactionEncoder.matchOrdersTx(leftSignedOrder, rightSignedOrder); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + const transaction = await this._toSignedZeroExTransactionAsync(data, takerAddress); + return this._sendTransactionAsync( + transaction, + takerAddress, + transaction.signature, + [], + [], + orderTransactionOpts, + ); } /** - * Cancel a given order. + * Soft cancel a given order. See [soft cancels](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#soft-cancels). + * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. + * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). + */ + @decorators.asyncZeroExErrorHandler + public async softCancelOrderAsync(order: Order | SignedOrder): Promise { + assert.doesConformToSchema('order', order, schemas.orderSchema); + assert.isETHAddressHex('feeRecipientAddress', order.feeRecipientAddress); + assert.isSenderAddressAsync('makerAddress', order.makerAddress, this._web3Wrapper); + const data = this._transactionEncoder.cancelOrderTx(order); + + const transaction = await this._toSignedZeroExTransactionAsync(data, order.makerAddress); + return (await this._requestServerResponseAsync( + transaction, + order.makerAddress, + order.feeRecipientAddress, + )) as CoordinatorServerCancellationResponse; + } + + /** + * Batch version of softCancelOrderAsync. Requests multiple soft cancels + * @param orders An array of orders to cancel. + * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). + */ + @decorators.asyncZeroExErrorHandler + public async batchSoftCancelOrdersAsync(orders: SignedOrder[]): Promise { + assert.doesConformToSchema('orders', orders, schemas.ordersSchema); + const feeRecipientAddress = getFeeRecipientOrThrow(orders); + const makerAddress = getMakerAddressOrThrow(orders); + assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress); + assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); + + const data = this._transactionEncoder.batchCancelOrdersTx(orders); + const transaction = await this._toSignedZeroExTransactionAsync(data, makerAddress); + return (await this._requestServerResponseAsync( + transaction, + makerAddress, + feeRecipientAddress, + )) as CoordinatorServerCancellationResponse; + } + + /** + * Hard cancellation on Exchange contract. Cancels a single order. * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. */ @decorators.asyncZeroExErrorHandler - public async cancelOrderAsync( + public async hardCancelOrderAsync( order: Order | SignedOrder, orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, ): Promise { assert.doesConformToSchema('order', order, schemas.orderSchema); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('makerAddress', order.makerAddress, this._web3Wrapper); + const data = this._transactionEncoder.cancelOrderTx(order); - return this._handleFillAsync(data, order.makerAddress, order.feeRecipientAddress, orderTransactionOpts); // todo: is this the right taker address? + const transaction = await this._toSignedZeroExTransactionAsync(data, order.makerAddress); + return this._sendTransactionAsync( + transaction, + order.makerAddress, + transaction.signature, + [], + [], + orderTransactionOpts, + ); } /** + * Hard cancellation on Exchange contract. * Batch version of cancelOrderAsync. Executes multiple cancels atomically in a single transaction. * @param orders An array of orders to cancel. * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. */ @decorators.asyncZeroExErrorHandler - public async batchCancelOrdersAsync( + public async batchHardCancelOrdersAsync( orders: SignedOrder[], orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, ): Promise { assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - const makerAddresses = orders.map(o => o.makerAddress); - const makerAddress = makerAddresses[0]; - const feeRecipientAddress = getFeeRecipientOrThrow(orders); + const makerAddress = getMakerAddressOrThrow(orders); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); + const data = this._transactionEncoder.batchCancelOrdersTx(orders); - return this._handleFillAsync(data, makerAddress, feeRecipientAddress, orderTransactionOpts); + const transaction = await this._toSignedZeroExTransactionAsync(data, makerAddress); + return this._sendTransactionAsync( + transaction, + makerAddress, + transaction.signature, + [], + [], + orderTransactionOpts, + ); } /** + * Hard cancellation on Exchange contract. * Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch * and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). * @param targetOrderEpoch Target order epoch. @@ -403,47 +461,136 @@ export class CoordinatorWrapper extends ContractWrapper { * @return Transaction hash. */ @decorators.asyncZeroExErrorHandler - public async cancelOrdersUpToAsync( + public async hardCancelOrdersUpToAsync( targetOrderEpoch: BigNumber, senderAddress: string, - coordinatorOperatorAddress: string, orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, ): Promise { assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); - const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); - return this._handleFillAsync(data, senderAddress, coordinatorOperatorAddress, orderTransactionOpts); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); + return this._exchangeInstance.cancelOrdersUpTo.sendTransactionAsync(targetOrderEpoch, { + from: senderAddress, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, + }); + // // todo: find out why this doesn't work (xianny) + // const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); + // const transaction = await this._toSignedZeroExTransactionAsync(data, senderAddress); + // return this._sendTransactionAsync( + // transaction, + // senderAddress, + // transaction.signature, + // [], + // [], + // orderTransactionOpts, + // ); } - /** - * Executes a 0x transaction. Transaction messages exist for the purpose of calling methods on the Exchange contract - * in the context of another address (see [ZEIP18](https://github.com/0xProject/ZEIPs/issues/18)). - * This is especially useful for implementing filter contracts. - * @param salt Salt - * @param signerAddress Signer address - * @param data Transaction data - * @param signature Signature - * @param takerAddress Sender address - * @param feeRecipientAddress Coordinator operator address registered in CoordinatorRegistryContract - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async executeTransactionWithApprovalAsync( - salt: BigNumber, - signerAddress: string, - data: string, + public async assertValidCoordinatorApprovalsAsync( + transaction: ZeroExTransaction, + txOrigin: string, signature: string, - takerAddress: string, - feeRecipientAddress: string, + approvalExpirationTimeSeconds: BigNumber[], + approvalSignatures: string[], + ): Promise { + assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema); + assert.isETHAddressHex('txOrigin', txOrigin); + assert.isHexString('signature', signature); + for (const expirationTime of approvalExpirationTimeSeconds) { + assert.isBigNumber('expirationTime', expirationTime); + } + for (const approvalSignature of approvalSignatures) { + assert.isHexString('approvalSignature', approvalSignature); + } + + return this._contractInstance.assertValidCoordinatorApprovals.callAsync( + transaction, + txOrigin, + signature, + approvalExpirationTimeSeconds, + approvalSignatures, + ); + } + + public async getSignerAddressAsync(hash: string, signature: string): Promise { + assert.isHexString('hash', hash); + assert.isHexString('signature', signature); + return this._contractInstance.getSignerAddress.callAsync(hash, signature); + } + + private async _sendTransactionAsync( + transaction: { salt: BigNumber; signerAddress: string; data: string }, + txOrigin: string, + transactionSignature: string, + approvalExpirationTimeSeconds: BigNumber[], + approvalSignatures: string[], orderTransactionOpts: OrderTransactionOpts, ): Promise { - assert.isBigNumber('salt', salt); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.isHexString('data', data); - assert.isHexString('signature', signature); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + if (orderTransactionOpts.shouldValidate) { + await this._contractInstance.executeTransaction.callAsync( + transaction, + txOrigin, + transactionSignature, + approvalExpirationTimeSeconds, + approvalSignatures, + { + from: txOrigin, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, + }, + ); + } + const txHash = await this._contractInstance.executeTransaction.sendTransactionAsync( + transaction, + txOrigin, + transactionSignature, + approvalExpirationTimeSeconds, + approvalSignatures, + { + from: txOrigin, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, + }, + ); + return txHash; + } + + private async _toSignedZeroExTransactionAsync( + data: string, + senderAddress: string, + ): Promise { + await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); + const normalizedSenderAddress = senderAddress.toLowerCase(); + + const transaction: ZeroExTransaction = { + salt: generatePseudoRandomSalt(), + signerAddress: normalizedSenderAddress, + data, + verifyingContractAddress: this.exchangeAddress, + }; + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + const signature = await signatureUtils.ecSignHashAsync( + this._web3Wrapper.getProvider(), + transactionHash, + transaction.signerAddress, + ); + return { + ...transaction, + signature, + }; + } + + private async _requestServerResponseAsync( + transaction: SignedZeroExTransaction, + senderAddress: string, + feeRecipientAddress: string, + ): Promise { + assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema); assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); const coordinatorOperatorEndpoint = await this._registryInstance.getCoordinatorEndpoint.callAsync( feeRecipientAddress, @@ -456,20 +603,9 @@ export class CoordinatorWrapper extends ContractWrapper { ); } - const txOrigin = takerAddress; - const zeroExTransaction = { - salt, - signerAddress, - data, - }; - const requestPayload = { - signedTransaction: { - ...zeroExTransaction, - signature, - verifyingContractAddress: this.exchangeAddress, - }, - txOrigin, + signedTransaction: transaction, + txOrigin: senderAddress, }; const response = await fetchAsync( `${coordinatorOperatorEndpoint}/v1/request_transaction?networkId=${this.networkId}`, @@ -483,25 +619,10 @@ export class CoordinatorWrapper extends ContractWrapper { ); if (response.status !== HTTP_OK) { - throw new Error(``); // todo + throw new Error(`${response.status}: ${JSON.stringify(await response.json())}`); // todo } - const { signatures, expirationTimeSeconds } = (await response.json()) as CoordinatorServerResponse; - - console.log(`signatures, expiration: ${JSON.stringify(signatures)}, ${JSON.stringify(expirationTimeSeconds)}`); - return this._contractInstance.executeTransaction.sendTransactionAsync( - zeroExTransaction, - txOrigin, - signature, - [expirationTimeSeconds], - signatures, - { - from: txOrigin, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); + return (await response.json()) as CoordinatorServerApprovalResponse | CoordinatorServerCancellationResponse; } private async _handleFillAsync( @@ -512,28 +633,20 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const transaction: ZeroExTransaction = { - salt: generatePseudoRandomSalt(), - signerAddress: normalizedTakerAddress, - data, - verifyingContractAddress: this.exchangeAddress, - }; - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const signature = await signatureUtils.ecSignHashAsync( - this._web3Wrapper.getProvider(), - transactionHash, - transaction.signerAddress, - ); - return this.executeTransactionWithApprovalAsync( - transaction.salt, - normalizedTakerAddress, - data, - signature, - normalizedTakerAddress, + const transaction = await this._toSignedZeroExTransactionAsync(data, takerAddress); + const { signatures, expirationTimeSeconds } = (await this._requestServerResponseAsync( + transaction, + takerAddress, feeRecipientAddress, + )) as CoordinatorServerApprovalResponse; + + return this._sendTransactionAsync( + transaction, + takerAddress, + transaction.signature, + [expirationTimeSeconds], + signatures, orderTransactionOpts, ); } @@ -542,7 +655,17 @@ export class CoordinatorWrapper extends ContractWrapper { function getFeeRecipientOrThrow(orders: Array): string { const uniqueFeeRecipients = new Set(orders.map(o => o.feeRecipientAddress)); if (uniqueFeeRecipients.size > 1) { - throw new Error(`All orders in a batch must have the same feeRecipientAddress (a valid coordinator operator address)`); + throw new Error( + `All orders in a batch must have the same feeRecipientAddress (a valid coordinator operator address)`, + ); } return orders[0].feeRecipientAddress; } + +function getMakerAddressOrThrow(orders: Array): string { + const uniqueMakerAddresses = new Set(orders.map(o => o.makerAddress)); + if (uniqueMakerAddresses.size > 1) { + throw new Error(`All orders in a batch must have the same makerAddress`); + } + return orders[0].makerAddress; +} diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index c3cee1be90..b1a242bc3e 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -226,7 +226,19 @@ export interface DutchAuctionData { beginAmount: BigNumber; } -export interface CoordinatorServerResponse { +export interface CoordinatorServerApprovalResponse { signatures: string[]; expirationTimeSeconds: BigNumber; } + +export interface CoordinatorServerCancellationResponse { + outstandingFillSignatures: [ + { + orderHash: string; + approvalSignatures: string[]; + expirationTimeSeconds: BigNumber; + takerAssetFillAmount: BigNumber; + } + ]; + cancellationSignatures: string[]; +} diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 6cae0a4c9d..0d534e021a 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -24,7 +24,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); const coordinatorEndpoint = 'http://localhost:3000'; // tslint:disable:custom-no-magic-numbers -describe.only('CoordinatorWrapper', () => { +describe('CoordinatorWrapper', () => { const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); let app: http.Server; @@ -44,7 +44,6 @@ describe.only('CoordinatorWrapper', () => { let txHash: string; let signedOrder: SignedOrder; let anotherSignedOrder: SignedOrder; - let signedOrderWithoutFeeRecipient: SignedOrder; let coordinatorRegistryInstance: CoordinatorRegistryContract; before(async () => { const contractAddresses = await migrateOnceAsync(); @@ -67,39 +66,11 @@ describe.only('CoordinatorWrapper', () => { contractWrappers.erc721Proxy.address, ); [, makerAddress, takerAddress, feeRecipientAddress, anotherFeeRecipientAddress] = userAddresses.slice(0, 5); - [makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - takerTokenAddress = contractWrappers.forwarder.etherTokenAddress; + [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); [makerAssetData, takerAssetData] = [ assetDataUtils.encodeERC20AssetData(makerTokenAddress), assetDataUtils.encodeERC20AssetData(takerTokenAddress), ]; - signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerAssetData, - takerAssetData, - new BigNumber(1), - new BigNumber(1), - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - feeRecipientAddress, - ); - anotherSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerAssetData, - takerAssetData, - new BigNumber(1), - new BigNumber(1), - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - feeRecipientAddress, - ); - signedOrderWithoutFeeRecipient = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - ); // set up mock coordinator server const coordinatorServerConfigs = { @@ -109,11 +80,15 @@ describe.only('CoordinatorWrapper', () => { FEE_RECIPIENTS: [ { ADDRESS: feeRecipientAddress, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddress)].toString('hex'), + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[ + userAddresses.indexOf(feeRecipientAddress) + ].toString('hex'), }, { ADDRESS: anotherFeeRecipientAddress, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(anotherFeeRecipientAddress)].toString('hex'), + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[ + userAddresses.indexOf(anotherFeeRecipientAddress) + ].toString('hex'), }, ], // Ethereum RPC url, only used in the default instantiation in server.js of 0x-coordinator-server @@ -132,7 +107,8 @@ describe.only('CoordinatorWrapper', () => { coordinatorServerConfigs, ); - await app.listen(coordinatorServerConfigs.HTTP_PORT, () => { // tslint:disable-line:await-promise + await app.listen(coordinatorServerConfigs.HTTP_PORT, () => { + // tslint:disable-line:await-promise console.log(`Coordinator SERVER API (HTTP) listening on port ${coordinatorServerConfigs.HTTP_PORT}!`); // tslint:disable-line:no-console }); @@ -141,13 +117,13 @@ describe.only('CoordinatorWrapper', () => { CoordinatorRegistry.compilerOutput.abi, contractAddresses.coordinatorRegistry, provider, - {gas: 6000000}); + { gas: 6000000 }, + ); await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync( - coordinatorEndpoint, - { from: feeRecipientAddress }, - ), + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync(coordinatorEndpoint, { + from: feeRecipientAddress, + }), constants.AWAIT_TRANSACTION_MINED_MS, ); }); @@ -156,6 +132,26 @@ describe.only('CoordinatorWrapper', () => { }); beforeEach(async () => { await blockchainLifecycle.startAsync(); + signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + takerAddress, + fillableAmount, + feeRecipientAddress, + ); + anotherSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + takerAddress, + fillableAmount, + feeRecipientAddress, + ); }); afterEach(async () => { await blockchainLifecycle.revertAsync(); @@ -219,7 +215,7 @@ describe.only('CoordinatorWrapper', () => { }); }); describe('#marketBuyOrdersAsync', () => { - it('should maker buy', async () => { + it('should market buy', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const makerAssetFillAmount = takerTokenFillAmount; txHash = await contractWrappers.coordinator.marketBuyOrdersAsync( @@ -231,7 +227,7 @@ describe.only('CoordinatorWrapper', () => { }); }); describe('#marketBuyOrdersNoThrowAsync', () => { - it('should no throw maker buy', async () => { + it('should no throw market buy', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const makerAssetFillAmount = takerTokenFillAmount; txHash = await contractWrappers.coordinator.marketBuyOrdersNoThrowAsync( @@ -245,7 +241,7 @@ describe.only('CoordinatorWrapper', () => { }); }); describe('#marketSellOrdersAsync', () => { - it('should maker sell', async () => { + it('should market sell', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const takerAssetFillAmount = takerTokenFillAmount; txHash = await contractWrappers.coordinator.marketSellOrdersAsync( @@ -257,7 +253,7 @@ describe.only('CoordinatorWrapper', () => { }); }); describe('#marketSellOrdersNoThrowAsync', () => { - it('should no throw maker sell', async () => { + it('should no throw market sell', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const takerAssetFillAmount = takerTokenFillAmount; txHash = await contractWrappers.coordinator.marketSellOrdersNoThrowAsync( @@ -307,7 +303,7 @@ describe.only('CoordinatorWrapper', () => { takerAddress, fillableAmount, ); - txHash = await contractWrappers.coordinator.matchOrdersAsync( + txHash = await contractWrappers.exchange.matchOrdersAsync( signedOrder, matchingSignedOrder, takerAddress, @@ -316,31 +312,48 @@ describe.only('CoordinatorWrapper', () => { }); }); }); - // describe('cancel order(s)', () => { - // describe('#cancelOrderAsync', () => { - // it('should cancel a valid order', async () => { - // txHash = await contractWrappers.coordinator.cancelOrderAsync(signedOrder); - // await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - // }); - // }); - // describe('#batchCancelOrdersAsync', () => { - // it('should cancel a batch of valid orders', async () => { - // const orders = [signedOrder, anotherSignedOrder]; - // txHash = await contractWrappers.coordinator.batchCancelOrdersAsync(orders); - // await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - // }); - // }); - // describe('#cancelOrdersUpTo/getOrderEpochAsync', () => { - // it('should cancel orders up to target order epoch', async () => { - // const targetOrderEpoch = new BigNumber(42); - // txHash = await contractWrappers.coordinator.cancelOrdersUpToAsync(targetOrderEpoch, makerAddress); - // await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - // const orderEpoch = await contractWrappers.coordinator.getOrderEpochAsync( - // makerAddress, - // constants.NULL_ADDRESS, - // ); - // expect(orderEpoch).to.be.bignumber.equal(targetOrderEpoch.plus(1)); - // }); - // }); - // }); + describe('soft cancel order(s)', () => { + describe('#softCancelOrderAsync', () => { + it('should cancel a valid order', async () => { + const response = await contractWrappers.coordinator.softCancelOrderAsync(signedOrder); + expect(response.outstandingFillSignatures).to.have.lengthOf(0); + expect(response.cancellationSignatures).to.have.lengthOf(1); + }); + }); + describe('#batchSoftCancelOrdersAsync', () => { + it('should cancel a batch of valid orders', async () => { + const orders = [signedOrder, anotherSignedOrder]; + const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); + expect(response.outstandingFillSignatures).to.have.lengthOf(0); + expect(response.cancellationSignatures).to.have.lengthOf(1); + }); + }); + }); + describe('hard cancel order(s)', () => { + describe('#hardCancelOrderAsync', () => { + it('should cancel a valid order', async () => { + txHash = await contractWrappers.coordinator.hardCancelOrderAsync(signedOrder); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#batchHardCancelOrdersAsync', () => { + it('should cancel a batch of valid orders', async () => { + const orders = [signedOrder, anotherSignedOrder]; + txHash = await contractWrappers.coordinator.batchHardCancelOrdersAsync(orders); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#cancelOrdersUpTo/getOrderEpochAsync', () => { + it('should cancel orders up to target order epoch', async () => { + const targetOrderEpoch = new BigNumber(42); + txHash = await contractWrappers.coordinator.hardCancelOrdersUpToAsync(targetOrderEpoch, makerAddress); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + const orderEpoch = await contractWrappers.exchange.getOrderEpochAsync( + makerAddress, + constants.NULL_ADDRESS, + ); + expect(orderEpoch).to.be.bignumber.equal(targetOrderEpoch.plus(1)); + }); + }); + }); }); diff --git a/yarn.lock b/yarn.lock index c448a562dd..7a053df770 100644 --- a/yarn.lock +++ b/yarn.lock @@ -489,6 +489,30 @@ ethers "~4.0.4" lodash "^4.17.11" +"@0x/contract-wrappers@^8.0.5": + version "8.0.5" + resolved "https://registry.yarnpkg.com/@0x/contract-wrappers/-/contract-wrappers-8.0.5.tgz#2bad814956625b740403a903d459a6e58fc77b92" + integrity sha512-lz67pqZIN6nY0mAsIAeaii3k4JPtHRlfPl5hZAOyw3VzsrYPQ5u09rLWB04hRjSx4Ibmj6c1NLTpFLat/7bXlA== + dependencies: + "@0x/abi-gen-wrappers" "^4.1.0" + "@0x/assert" "^2.0.8" + "@0x/contract-addresses" "^2.3.0" + "@0x/contract-artifacts" "^1.4.0" + "@0x/json-schemas" "^3.0.8" + "@0x/order-utils" "^7.1.1" + "@0x/types" "^2.2.1" + "@0x/typescript-typings" "^4.2.1" + "@0x/utils" "^4.3.0" + "@0x/web3-wrapper" "^6.0.4" + ethereum-types "^2.1.1" + ethereumjs-abi "0.6.5" + ethereumjs-blockstream "6.0.0" + ethereumjs-util "^5.1.1" + ethers "~4.0.4" + js-sha3 "^0.7.0" + lodash "^4.17.11" + uuid "^3.3.2" + "@0x/contracts-asset-proxy@^1.0.2": version "1.0.9" resolved "https://registry.npmjs.org/@0x/contracts-asset-proxy/-/contracts-asset-proxy-1.0.9.tgz#3a48e64b93ddc642834bde1bd09cdd84ca688a2b" @@ -637,6 +661,37 @@ ethereumjs-util "^5.1.1" lodash "^4.17.11" +"@0x/coordinator-server@^0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-0.0.6.tgz#8a8544037b4275d3a39d0d4698fc10e792fc945e" + integrity sha512-i4FamF4ZW5HkgrLakN3XI3AqGLKCq0H+dC9tqg5Wf1EeFQNU5r/R8matx7hTav8SW98Fys8qG9c5NFqPcCmljg== + dependencies: + "@0x/assert" "^2.0.8" + "@0x/asset-buyer" "^6.0.5" + "@0x/contract-addresses" "^2.3.0" + "@0x/contract-wrappers" "^8.0.5" + "@0x/contracts-erc20" "^2.1.0" + "@0x/json-schemas" "^3.0.8" + "@0x/order-utils" "^7.1.1" + "@0x/subproviders" "^4.0.4" + "@0x/types" "^2.2.1" + "@0x/typescript-typings" "^4.2.1" + "@0x/utils" "^4.3.0" + "@0x/web3-wrapper" "^6.0.4" + "@babel/polyfill" "^7.0.0" + body-parser "^1.18.3" + cors "^2.8.5" + express "^4.16.3" + express-async-handler "^1.1.4" + forever "^0.15.3" + http-status-codes "^1.3.0" + jsonschema "^1.2.4" + lodash "^4.17.11" + reflect-metadata "^0.1.10" + sqlite3 "^4.0.2" + typeorm "0.2.7" + websocket "^1.0.25" + "@0x/order-utils@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-5.0.0.tgz#7f43e0310ace31738895881501c8dda9c3a3aefa" @@ -719,6 +774,14 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/polyfill@^7.0.0": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.4.3.tgz#332dc6f57b718017c3a8b37b4eea8aa6eeac1187" + integrity sha512-rkv8WIvJshA5Ev8iNMGgz5WZkRtgtiPexiT7w5qevGTuT7ZBfM3de9ox1y9JR5/OXb/sWGBbWlHNa7vQKqku3Q== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.2" + "@babel/runtime@7.0.0", "@babel/runtime@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c" @@ -1484,6 +1547,11 @@ version "3.0.0" resolved "https://registry.yarnpkg.com/@types/compare-versions/-/compare-versions-3.0.0.tgz#4a45dffe0ebbc00d0f2daef8a0e96ffc66cf5955" +"@types/cookiejar@*": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" + integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== + "@types/deep-equal@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.1.tgz#71cfabb247c22bcc16d536111f50c0ed12476b03" @@ -1939,6 +2007,21 @@ "@types/react" "*" csstype "^2.2.0" +"@types/superagent@*": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.1.tgz#61f0b43d7db93a3c286c124512b7c228183c32fa" + integrity sha512-NetXrraTWPcdGG6IwYJhJ5esUGx8AYNiozbc1ENWEsF6BsD4JmNODJczI6Rm1xFPVp6HZESds9YCfqz4zIsM6A== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +"@types/supertest@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.7.tgz#46ff6508075cd4519736be060f0d6331a5c8ca7b" + integrity sha512-GibTh4OTkal71btYe2fpZP/rVHIPnnUsYphEaoywVHo+mo2a/LhlOFkIm5wdN0H0DA0Hx8x+tKgCYMD9elHu5w== + dependencies: + "@types/superagent" "*" + "@types/tapable@*": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" @@ -2608,6 +2691,16 @@ async-parallel@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/async-parallel/-/async-parallel-1.2.3.tgz#0b90550aeffb7a365d8cee881eb0618f656a3450" +async@0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.9.tgz#df63060fbf3d33286a76aaf6d55a2986d9ff8619" + integrity sha1-32MGD789Myhqdqr21Vophtn/hhk= + +async@0.2.x, async@~0.2.9: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= + async@1.x, async@^1.4.0, async@^1.4.2, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -3663,7 +3756,7 @@ body-parser@1.18.2, body-parser@^1.16.0, body-parser@^1.17.1: raw-body "2.3.2" type-is "~1.6.15" -body-parser@1.18.3: +body-parser@1.18.3, body-parser@^1.18.3: version "1.18.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" dependencies: @@ -3769,6 +3862,17 @@ brcast@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/brcast/-/brcast-3.0.1.tgz#6256a8349b20de9eed44257a9b24d71493cd48dd" +broadway@~0.3.2, broadway@~0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/broadway/-/broadway-0.3.6.tgz#7dbef068b954b7907925fd544963b578a902ba7a" + integrity sha1-fb7waLlUt5B5Jf1USWO1eKkCuno= + dependencies: + cliff "0.1.9" + eventemitter2 "0.4.14" + nconf "0.6.9" + utile "0.2.1" + winston "0.8.0" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -4083,6 +4187,13 @@ call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" +caller@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/caller/-/caller-0.0.1.tgz#f37a1d6ea10e829d94721ae29a90bb4fb52ab767" + integrity sha1-83odbqEOgp2UchrimpC7T7Uqt2c= + dependencies: + tape "~2.3.2" + callsites@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" @@ -4466,6 +4577,24 @@ cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" +cliff@0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/cliff/-/cliff-0.1.9.tgz#a211e09c6a3de3ba1af27d049d301250d18812bc" + integrity sha1-ohHgnGo947oa8n0EnTASUNGIErw= + dependencies: + colors "0.x.x" + eyes "0.1.x" + winston "0.8.x" + +cliff@~0.1.9: + version "0.1.10" + resolved "https://registry.yarnpkg.com/cliff/-/cliff-0.1.10.tgz#53be33ea9f59bec85609ee300ac4207603e52013" + integrity sha1-U74z6p9ZvshWCe4wCsQgdgPlIBM= + dependencies: + colors "~1.0.3" + eyes "~0.1.8" + winston "0.8.x" + clipboard@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/clipboard/-/clipboard-2.0.1.tgz#a12481e1c13d8a50f5f036b0560fe5d16d74e46a" @@ -4609,7 +4738,12 @@ colors@0.5.x: version "0.5.1" resolved "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774" -colors@1.0.x: +colors@0.6.x, colors@0.x.x, colors@~0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + integrity sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w= + +colors@1.0.x, colors@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" @@ -4634,6 +4768,13 @@ combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5, combined- dependencies: delayed-stream "~1.0.0" +combined-stream@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + comma-separated-tokens@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.5.tgz#b13793131d9ea2d2431cf5b507ddec258f0ce0db" @@ -4695,6 +4836,11 @@ component-classes@^1.2.5: dependencies: component-indexof "0.0.3" +component-emitter@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -4967,7 +5113,7 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" -cookiejar@^2.1.1: +cookiejar@^2.1.0, cookiejar@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" @@ -5024,6 +5170,11 @@ core-js@^2.4.0, core-js@^2.5.0: version "2.5.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b" +core-js@^2.6.5: + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -5035,6 +5186,14 @@ cors@^2.8.1: object-assign "^4" vary "^1" +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^5.0.2: version "5.0.5" resolved "http://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.5.tgz#a809e3c2306891ce17ab70359dc8bdf661fe2cd0" @@ -5520,10 +5679,15 @@ deep-eql@^3.0.0: dependencies: type-detect "^4.0.0" -deep-equal@^1.0.1, deep-equal@~1.0.1: +deep-equal@*, deep-equal@^1.0.1, deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" +deep-equal@~0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.1.2.tgz#b246c2b80a570a47c11be1d9bd1070ec878b87ce" + integrity sha1-skbCuApXCkfBG+HZvRBw7IeLh84= + deep-equal@~0.2.1: version "0.2.2" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" @@ -5606,6 +5770,11 @@ defined@^1.0.0, defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" +defined@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e" + integrity sha1-817qfXBekzuvE7LwOz+D2SFAOz4= + del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -5748,6 +5917,11 @@ dir-glob@^2.0.0: arrify "^1.0.1" path-type "^3.0.0" +director@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/director/-/director-1.2.7.tgz#bfd3741075fd7fb1a5b2e13658c5f4bec77736f3" + integrity sha1-v9N0EHX9f7GlsuE2WMX0vsd3NvM= + dirty-chai@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/dirty-chai/-/dirty-chai-2.0.1.tgz#6b2162ef17f7943589da840abc96e75bda01aff3" @@ -6754,6 +6928,13 @@ ev-emitter@^1.0.0, ev-emitter@^1.0.1, ev-emitter@^1.0.2: version "1.1.1" resolved "https://registry.yarnpkg.com/ev-emitter/-/ev-emitter-1.1.1.tgz#8f18b0ce5c76a5d18017f71c0a795c65b9138f2a" +event-stream@~0.5: + version "0.5.3" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-0.5.3.tgz#b77b9309f7107addfeab63f0c0eafd8db0bd8c1c" + integrity sha1-t3uTCfcQet3+q2PwwOr9jbC9jBw= + dependencies: + optimist "0.2" + event-stream@~3.3.0: version "3.3.4" resolved "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -6766,6 +6947,11 @@ event-stream@~3.3.0: stream-combiner "~0.0.4" through "~2.3.1" +eventemitter2@0.4.14, eventemitter2@~0.4.14: + version "0.4.14" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" + integrity sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas= + eventemitter3@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.1.1.tgz#47786bdaa087caf7b1b75e73abc5c7d540158cd0" @@ -6914,6 +7100,11 @@ expect@^23.6.0: jest-message-util "^23.4.0" jest-regex-util "^23.3.0" +express-async-handler@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/express-async-handler/-/express-async-handler-1.1.4.tgz#225a84908df63b35ae9df94b6f0f1af061266426" + integrity sha512-HdmbVF4V4w1q/iz++RV7bUxIeepTukWewiJGkoCKQMtvPF11MLTa7It9PRc/reysXXZSEyD4Pthchju+IUbMiQ== + express@^4.14.0, express@^4.15.2, express@^4.16.2: version "4.16.3" resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" @@ -7055,7 +7246,7 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" -eyes@0.1.x: +eyes@0.1.x, eyes@~0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" @@ -7363,6 +7554,16 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +flatiron@~0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/flatiron/-/flatiron-0.4.3.tgz#248cf79a3da7d7dc379e2a11c92a2719cbb540f6" + integrity sha1-JIz3mj2n19w3nioRySonGcu1QPY= + dependencies: + broadway "~0.3.2" + director "1.2.7" + optimist "0.6.0" + prompt "0.2.14" + flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" @@ -7435,6 +7636,47 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" +forever-monitor@~1.7.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/forever-monitor/-/forever-monitor-1.7.1.tgz#5d820f4a3a78db2d81ae2671f158b9e86a091bb8" + integrity sha1-XYIPSjp42y2BriZx8Vi56GoJG7g= + dependencies: + broadway "~0.3.6" + chokidar "^1.0.1" + minimatch "~3.0.2" + ps-tree "0.0.x" + utile "~0.2.1" + +forever@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/forever/-/forever-0.15.3.tgz#77d9d7e15fd2f511ad9d84a110c7dd8fc8ecebc2" + integrity sha1-d9nX4V/S9RGtnYShEMfdj8js68I= + dependencies: + cliff "~0.1.9" + clone "^1.0.2" + colors "~0.6.2" + flatiron "~0.4.2" + forever-monitor "~1.7.0" + nconf "~0.6.9" + nssocket "~0.5.1" + object-assign "^3.0.0" + optimist "~0.6.0" + path-is-absolute "~1.0.0" + prettyjson "^1.1.2" + shush "^1.0.0" + timespan "~2.3.0" + utile "~0.2.1" + winston "~0.8.1" + +form-data@^2.3.1: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + form-data@~2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" @@ -7459,6 +7701,11 @@ format@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" +formidable@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" + integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -8058,6 +8305,7 @@ got@^6.7.1: graceful-fs@4.1.15, graceful-fs@^3.0.0, graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~1.2.0: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== "graceful-readlink@>= 1.0.0": version "1.0.1" @@ -8573,6 +8821,11 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +http-status-codes@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.3.2.tgz#181dfa4455ef454e5e4d827718fca3936680d10d" + integrity sha512-nDUtj0ltIt08tGi2VWSpSzNNFye0v3YSe9lX3lIqLTuVvvRiYCvs4QQBSHo0eomFYw1wlUuofurUAlTm+vHnXg== + https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" @@ -8751,7 +9004,7 @@ inherits@2.0.1, inherits@=2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: +ini@1.x.x, ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -9990,7 +10243,7 @@ jsonschema-draft4@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/jsonschema-draft4/-/jsonschema-draft4-1.0.0.tgz#f0af2005054f0f0ade7ea2118614b69dc512d865" -jsonschema@*, jsonschema@1.2.4, jsonschema@^1.2.0: +jsonschema@*, jsonschema@1.2.4, jsonschema@^1.2.0, jsonschema@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.4.tgz#a46bac5d3506a254465bc548876e267c6d0d6464" @@ -10150,6 +10403,11 @@ lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" +lazy@~1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" + integrity sha1-2qBoIGKCVCwIgojpdcKXwa53tpA= + lazystream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" @@ -11160,7 +11418,7 @@ merkle-patricia-tree@^2.3.2: rlp "^2.0.0" semaphore ">=1.0.1" -methods@~1.1.2: +methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -11231,7 +11489,7 @@ mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" -mime@^1.2.11, mime@^1.3.4: +mime@^1.2.11, mime@^1.3.4, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -11261,7 +11519,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -11513,6 +11771,20 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" +nconf@0.6.9, nconf@~0.6.9: + version "0.6.9" + resolved "https://registry.yarnpkg.com/nconf/-/nconf-0.6.9.tgz#9570ef15ed6f9ae6b2b3c8d5e71b66d3193cd661" + integrity sha1-lXDvFe1vmuays8jV5xtm0xk81mE= + dependencies: + async "0.2.9" + ini "1.x.x" + optimist "0.6.0" + +ncp@0.4.x: + version "0.4.2" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.4.2.tgz#abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574" + integrity sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ= + ncp@1.0.x: version "1.0.1" resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" @@ -11904,6 +12176,14 @@ npmlog@~2.0.0: are-we-there-yet "~1.1.2" gauge "~1.2.5" +nssocket@~0.5.1: + version "0.5.3" + resolved "https://registry.yarnpkg.com/nssocket/-/nssocket-0.5.3.tgz#883ca2ec605f5ed64a4d5190b2625401928f8f8d" + integrity sha1-iDyi7GBfXtZKTVGQsmJUAZKPj40= + dependencies: + eventemitter2 "~0.4.14" + lazy "~1.0.11" + nth-check@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" @@ -12171,7 +12451,22 @@ opn@^5.1.0, opn@^5.3.0: dependencies: is-wsl "^1.1.0" -optimist@^0.6.1: +optimist@0.2: + version "0.2.8" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.2.8.tgz#e981ab7e268b457948593b55674c099a815cac31" + integrity sha1-6YGrfiaLRXlIWTtVZ0wJmoFcrDE= + dependencies: + wordwrap ">=0.0.1 <0.1.0" + +optimist@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.0.tgz#69424826f3405f79f142e6fc3d9ae58d4dbb9200" + integrity sha1-aUJIJvNAX3nxQub8PZrljU27kgA= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optimist@^0.6.1, optimist@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: @@ -12550,7 +12845,7 @@ path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1, path-is-absolute@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -13107,6 +13402,14 @@ pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" +prettyjson@^1.1.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" + integrity sha1-/P+rQdGcq0365eV15kJGYZsS0ok= + dependencies: + colors "^1.1.2" + minimist "^1.2.0" + prismjs@^1.15.0, prismjs@^1.8.4, prismjs@~1.15.0: version "1.15.0" resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.15.0.tgz#8801d332e472091ba8def94976c8877ad60398d9" @@ -13168,6 +13471,17 @@ promisify-child-process@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/promisify-child-process/-/promisify-child-process-1.0.5.tgz#817ad1aec92c013d83bb37e1f143e9b4033d9669" +prompt@0.2.14: + version "0.2.14" + resolved "https://registry.yarnpkg.com/prompt/-/prompt-0.2.14.tgz#57754f64f543fd7b0845707c818ece618f05ffdc" + integrity sha1-V3VPZPVD/XsIRXB8gY7OYY8F/9w= + dependencies: + pkginfo "0.x.x" + read "1.0.x" + revalidator "0.1.x" + utile "0.2.x" + winston "0.8.x" + prompt@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.0.0.tgz#8e57123c396ab988897fb327fd3aedc3e735e4fe" @@ -13241,6 +13555,13 @@ prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" +ps-tree@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-0.0.3.tgz#dbf8d752a7fe22fa7d58635689499610e9276ddc" + integrity sha1-2/jXUqf+Ivp9WGNWiUmWEOknbdw= + dependencies: + event-stream "~0.5" + ps-tree@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" @@ -13395,6 +13716,11 @@ qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" +qs@^6.5.1: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -13677,8 +14003,6 @@ react-highlight@0xproject/react-highlight#react-peer-deps: dependencies: highlight.js "^9.11.0" highlightjs-solidity "^1.0.5" - react "^16.5.2" - react-dom "^16.5.2" react-hot-loader@^4.3.3: version "4.3.4" @@ -14199,6 +14523,11 @@ redux@^3.6.0: loose-envify "^1.1.0" symbol-observable "^1.0.3" +reflect-metadata@^0.1.10: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + reflect-metadata@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" @@ -14223,6 +14552,11 @@ regenerator-runtime@^0.12.0: version "0.12.1" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" +regenerator-runtime@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" + integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -15105,6 +15439,14 @@ shellwords@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" +shush@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shush/-/shush-1.0.0.tgz#c27415a9e458f2fed39b27cf8eb37c003782b431" + integrity sha1-wnQVqeRY8v7TmyfPjrN8ADeCtDE= + dependencies: + caller "~0.0.1" + strip-json-comments "~0.1.1" + shx@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/shx/-/shx-0.2.2.tgz#0a304d020b0edf1306ad81570e80f0346df58a39" @@ -15787,6 +16129,11 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" +strip-json-comments@~0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-0.1.3.tgz#164c64e370a8a3cc00c9e01b539e569823f0ee54" + integrity sha1-Fkxk43Coo8wAyeAbU55WmCPw7lQ= + strong-log-transformer@^1.0.6: version "1.0.6" resolved "http://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-1.0.6.tgz#f7fb93758a69a571140181277eea0c2eb1301fa3" @@ -15854,6 +16201,30 @@ stylis@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/stylis/-/stylis-3.5.0.tgz#016fa239663d77f868fef5b67cf201c4b7c701e1" +superagent@^3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" + integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== + dependencies: + component-emitter "^1.2.0" + cookiejar "^2.1.0" + debug "^3.1.0" + extend "^3.0.0" + form-data "^2.3.1" + formidable "^1.2.0" + methods "^1.1.1" + mime "^1.4.1" + qs "^6.5.1" + readable-stream "^2.3.5" + +supertest@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" + integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== + dependencies: + methods "^1.1.2" + superagent "^3.8.3" + supports-color@4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" @@ -16022,6 +16393,18 @@ tape@^4.4.0, tape@^4.6.3, tape@^4.8.0: string.prototype.trim "~1.1.2" through "~2.3.8" +tape@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tape/-/tape-2.3.3.tgz#2e7ce0a31df09f8d6851664a71842e0ca5057af7" + integrity sha1-Lnzgox3wn41oUWZKcYQuDKUFevc= + dependencies: + deep-equal "~0.1.0" + defined "~0.0.0" + inherits "~2.0.1" + jsonify "~0.0.0" + resumer "~0.0.0" + through "~2.3.4" + tar-fs@^1.13.0: version "1.16.0" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.0.tgz#e877a25acbcc51d8c790da1c57c9cf439817b896" @@ -16262,6 +16645,11 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +timespan@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" + integrity sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk= + tiny-emitter@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c" @@ -16614,6 +17002,25 @@ typemoq@^2.1.0: lodash "^4.17.4" postinstall-build "^5.0.1" +typeorm@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.7.tgz#4bbbace80dc91b1303be13f42d44ebf01d1b2558" + integrity sha512-D7JxOBSqBiLAPu/M/4v15J++3klAWcv5WvYgrfl0iaaGObZJ/8UXm3oTpOtQUHfwJO9Cja8JMiwT9G7dyvwrxg== + dependencies: + app-root-path "^2.0.1" + buffer "^5.1.0" + chalk "^2.3.2" + cli-highlight "^1.2.3" + debug "^3.1.0" + dotenv "^5.0.1" + glob "^7.1.2" + js-yaml "^3.11.0" + mkdirp "^0.5.1" + reflect-metadata "^0.1.12" + xml2js "^0.4.17" + yargonaut "^1.1.2" + yargs "^11.1.0" + typeorm@^0.2.7: version "0.2.11" resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.11.tgz#d81a295ed822e05043f2920cd539f52a963896b0" @@ -17026,6 +17433,18 @@ utila@^0.4.0, utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" +utile@0.2.1, utile@0.2.x, utile@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/utile/-/utile-0.2.1.tgz#930c88e99098d6220834c356cbd9a770522d90d7" + integrity sha1-kwyI6ZCY1iIINMNWy9mncFItkNc= + dependencies: + async "~0.2.9" + deep-equal "*" + i "0.3.x" + mkdirp "0.x.x" + ncp "0.4.x" + rimraf "2.x.x" + utile@0.3.x: version "0.3.0" resolved "https://registry.yarnpkg.com/utile/-/utile-0.3.0.tgz#1352c340eb820e4d8ddba039a4fbfaa32ed4ef3a" @@ -17766,7 +18185,7 @@ websocket@1.0.26: typedarray-to-buffer "^3.1.2" yaeti "^0.0.6" -websocket@^1.0.26: +websocket@^1.0.25, websocket@^1.0.26: version "1.0.28" resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.28.tgz#9e5f6fdc8a3fe01d4422647ef93abdd8d45a78d3" dependencies: @@ -17866,6 +18285,31 @@ window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" +winston@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-0.8.0.tgz#61d0830fa699706212206b0a2b5ca69a93043668" + integrity sha1-YdCDD6aZcGISIGsKK1ymmpMENmg= + dependencies: + async "0.2.x" + colors "0.6.x" + cycle "1.0.x" + eyes "0.1.x" + pkginfo "0.3.x" + stack-trace "0.0.x" + +winston@0.8.x, winston@~0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/winston/-/winston-0.8.3.tgz#64b6abf4cd01adcaefd5009393b1d8e8bec19db0" + integrity sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA= + dependencies: + async "0.2.x" + colors "0.6.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + pkginfo "0.3.x" + stack-trace "0.0.x" + winston@2.1.x: version "2.1.1" resolved "https://registry.yarnpkg.com/winston/-/winston-2.1.1.tgz#3c9349d196207fd1bdff9d4bc43ef72510e3a12e" @@ -17882,14 +18326,14 @@ wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +"wordwrap@>=0.0.1 <0.1.0", wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - worker-farm@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" @@ -18152,7 +18596,7 @@ yargs-parser@^9.0.2: dependencies: camelcase "^4.1.0" -yargs@11.1.0: +yargs@11.1.0, yargs@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" dependencies: From 1f3a925db5f545898ae87907d0d5266f5be9d022 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 25 Apr 2019 20:55:47 -0700 Subject: [PATCH 03/53] small cleanups --- packages/contract-wrappers/package.json | 2 -- .../src/contract_wrappers/coordinator_wrapper.ts | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index fa54ce1b06..85f3c7f6e4 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -79,7 +79,6 @@ "@0x/typescript-typings": "^4.2.2", "@0x/utils": "^4.3.1", "@0x/web3-wrapper": "^6.0.5", - "@types/supertest": "^2.0.7", "ethereum-types": "^2.1.2", "ethereumjs-abi": "0.6.5", "ethereumjs-blockstream": "6.0.0", @@ -87,7 +86,6 @@ "ethers": "~4.0.4", "js-sha3": "^0.7.0", "lodash": "^4.17.11", - "supertest": "^4.0.2", "uuid": "^3.3.2" }, "publishConfig": { diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 08ba7fe446..1d80b220f1 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -619,7 +619,7 @@ export class CoordinatorWrapper extends ContractWrapper { ); if (response.status !== HTTP_OK) { - throw new Error(`${response.status}: ${JSON.stringify(await response.json())}`); // todo + throw new Error(`${response.status}: ${JSON.stringify(await response.json())}`); // todo (xianny) } return (await response.json()) as CoordinatorServerApprovalResponse | CoordinatorServerCancellationResponse; @@ -650,7 +650,7 @@ export class CoordinatorWrapper extends ContractWrapper { orderTransactionOpts, ); } -} // tslint:disable:max-file-line-count +} function getFeeRecipientOrThrow(orders: Array): string { const uniqueFeeRecipients = new Set(orders.map(o => o.feeRecipientAddress)); @@ -669,3 +669,4 @@ function getMakerAddressOrThrow(orders: Array): string { } return orders[0].makerAddress; } + // tslint:disable:max-file-line-count From 1f2a9a9e9f0fe4484adeb6d18b913ae2cff204ed Mon Sep 17 00:00:00 2001 From: xianny Date: Fri, 26 Apr 2019 21:22:38 -0700 Subject: [PATCH 04/53] wip: improvements after review --- .../src/contract_wrappers.ts | 2 +- .../contract_wrappers/coordinator_wrapper.ts | 424 ++++++++++-------- .../test/coordinator_wrapper_test.ts | 202 ++++++--- yarn.lock | 129 +----- 4 files changed, 386 insertions(+), 371 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts index c375d32192..370a191d43 100644 --- a/packages/contract-wrappers/src/contract_wrappers.ts +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -76,7 +76,7 @@ export class ContractWrappers { public dutchAuction: DutchAuctionWrapper; /** - * An instance of the CoordinatorWrapper class containing methods for interacting with any Coordinator smart contract. + * An instance of the CoordinatorWrapper class containing methods for interacting with the Coordinator extension contract. */ public coordinator: CoordinatorWrapper; diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 1d80b220f1..45d12d3604 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -44,6 +44,8 @@ export class CoordinatorWrapper extends ContractWrapper { * @param networkId Desired networkId. * @param address The address of the Coordinator contract. If undefined, will * default to the known address corresponding to the networkId. + * @param exchangeAddress The address of the Exchange contract. If undefined, will + * default to the known address corresponding to the networkId. * @param registryAddress The address of the CoordinatorRegistry contract. If undefined, will * default to the known address corresponding to the networkId. */ @@ -87,7 +89,11 @@ export class CoordinatorWrapper extends ContractWrapper { } /** - * Fills a signed order with an amount denominated in baseUnits of the taker asset. + * Fills a signed order with an amount denominated in baseUnits of the taker asset. Under-the-hood, this + * method uses the `feeRecipientAddress` of the order to looks up the coordinator server endpoint registered in the + * coordinator registry contract. It requests a signature from that coordinator server before + * submitting the order and signature as a 0x transaction to the coordinator extension contract, which validates the + * signatures and then fills the order through the Exchange contract. * @param signedOrder An object that conforms to the SignedOrder interface. * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied @@ -104,8 +110,12 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const data = this._transactionEncoder.fillOrderTx(signedOrder, takerAssetFillAmount); - return this._handleFillAsync(data, takerAddress, signedOrder.feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, [signedOrder.feeRecipientAddress], orderTransactionOpts); } /** @@ -126,8 +136,12 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const data = this._transactionEncoder.fillOrderNoThrowTx(signedOrder, takerAssetFillAmount); - return this._handleFillAsync(data, takerAddress, signedOrder.feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, [signedOrder.feeRecipientAddress], orderTransactionOpts); } /** @@ -149,12 +163,22 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const data = this._transactionEncoder.fillOrKillOrderTx(signedOrder, takerAssetFillAmount); - return this._handleFillAsync(data, takerAddress, signedOrder.feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, [signedOrder.feeRecipientAddress], orderTransactionOpts); } /** * Batch version of fillOrderAsync. Executes multiple fills atomically in a single transaction. + * Under-the-hood, this + * method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints registered in the + * coordinator registry contract. It requests a signature from each coordinator server before + * submitting the orders and signatures as a 0x transaction to the coordinator extension contract, which validates the + * signatures and then fills the order through the Exchange contract. + * If any `feeRecipientAddress` in the batch is not registered to a coordinator server, the whole batch fails. * @param signedOrders An array of signed orders to fill. * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied @@ -173,9 +197,13 @@ export class CoordinatorWrapper extends ContractWrapper { for (const takerAssetFillAmount of takerAssetFillAmounts) { assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); } - const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + + const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.batchFillOrdersTx(signedOrders, takerAssetFillAmounts); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); } /** @@ -198,9 +226,13 @@ export class CoordinatorWrapper extends ContractWrapper { for (const takerAssetFillAmount of takerAssetFillAmounts) { assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); } - const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + + const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.batchFillOrdersNoThrowTx(signedOrders, takerAssetFillAmounts); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); } /** @@ -223,13 +255,23 @@ export class CoordinatorWrapper extends ContractWrapper { for (const takerAssetFillAmount of takerAssetFillAmounts) { assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); } - const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + + const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.batchFillOrKillOrdersTx(signedOrders, takerAssetFillAmounts); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); } /** * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. + * Under-the-hood, this + * method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints registered in the + * coordinator registry contract. It requests a signature from each coordinator server before + * submitting the orders and signatures as a 0x transaction to the coordinator extension contract, which validates the + * signatures and then fills the order through the Exchange contract. + * If any `feeRecipientAddress` in the batch is not registered to a coordinator server, the whole batch fails. * @param signedOrders An array of signed orders to fill. * @param makerAssetFillAmount Maker asset fill amount. * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied @@ -246,13 +288,23 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); - const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + + const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.marketBuyOrdersTx(signedOrders, makerAssetFillAmount); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); } /** * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. + * Under-the-hood, this + * method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints registered in the + * coordinator registry contract. It requests a signature from each coordinator server before + * submitting the orders and signatures as a 0x transaction to the coordinator extension contract, which validates the + * signatures and then fills the order through the Exchange contract. + * If any `feeRecipientAddress` in the batch is not registered to a coordinator server, the whole batch fails. * @param signedOrders An array of signed orders to fill. * @param takerAssetFillAmount Taker asset fill amount. * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied @@ -269,9 +321,13 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); - const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + const data = this._transactionEncoder.marketSellOrdersTx(signedOrders, takerAssetFillAmount); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + const feeRecipients = signedOrders.map(o => o.feeRecipientAddress); + return this._handleFillsAsync(data, takerAddress, feeRecipients, orderTransactionOpts); } /** @@ -292,9 +348,13 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); - const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); + + const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.marketBuyOrdersNoThrowTx(signedOrders, makerAssetFillAmount); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); } /** @@ -315,42 +375,13 @@ export class CoordinatorWrapper extends ContractWrapper { ): Promise { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); - const feeRecipientAddress = getFeeRecipientOrThrow(signedOrders); - const data = this._transactionEncoder.marketSellOrdersNoThrowTx(signedOrders, takerAssetFillAmount); - return this._handleFillAsync(data, takerAddress, feeRecipientAddress, orderTransactionOpts); - } - - /** - * Match two complementary orders that have a profitable spread. - * Each order is filled at their respective price point. However, the calculations are carried out as though - * the orders are both being filled at the right order's price point. - * The profit made by the left order goes to the taker (whoever matched the two orders). - * @param leftSignedOrder First order to match. - * @param rightSignedOrder Second order to match. - * @param takerAddress The address that sends the transaction and gets the spread. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async matchOrdersAsync( - leftSignedOrder: SignedOrder, - rightSignedOrder: SignedOrder, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('leftSignedOrder', leftSignedOrder, schemas.signedOrderSchema); - assert.doesConformToSchema('rightSignedOrder', rightSignedOrder, schemas.signedOrderSchema); + assert.isETHAddressHex('takerAddress', takerAddress); + assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.matchOrdersTx(leftSignedOrder, rightSignedOrder); - const transaction = await this._toSignedZeroExTransactionAsync(data, takerAddress); - return this._sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [], - [], - orderTransactionOpts, - ); + const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); + const data = this._transactionEncoder.marketSellOrdersNoThrowTx(signedOrders, takerAssetFillAmount); + return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); } /** @@ -363,13 +394,14 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('order', order, schemas.orderSchema); assert.isETHAddressHex('feeRecipientAddress', order.feeRecipientAddress); assert.isSenderAddressAsync('makerAddress', order.makerAddress, this._web3Wrapper); - const data = this._transactionEncoder.cancelOrderTx(order); - const transaction = await this._toSignedZeroExTransactionAsync(data, order.makerAddress); - return (await this._requestServerResponseAsync( + const data = this._transactionEncoder.cancelOrderTx(order); + const transaction = await this._generateSignedZeroExTransactionAsync(data, order.makerAddress); + const endpoints = await this._getServerEndpointsOrThrowAsync([order.feeRecipientAddress]); + return (await this._executeServerRequestAsync( transaction, order.makerAddress, - order.feeRecipientAddress, + endpoints[0], )) as CoordinatorServerCancellationResponse; } @@ -379,24 +411,23 @@ export class CoordinatorWrapper extends ContractWrapper { * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). */ @decorators.asyncZeroExErrorHandler - public async batchSoftCancelOrdersAsync(orders: SignedOrder[]): Promise { + public async batchSoftCancelOrdersAsync(orders: SignedOrder[]): Promise { assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - const feeRecipientAddress = getFeeRecipientOrThrow(orders); const makerAddress = getMakerAddressOrThrow(orders); - assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress); assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); const data = this._transactionEncoder.batchCancelOrdersTx(orders); - const transaction = await this._toSignedZeroExTransactionAsync(data, makerAddress); - return (await this._requestServerResponseAsync( + const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); + const endpoints = await this._getServerEndpointsOrThrowAsync(orders.map(o => o.feeRecipientAddress)); + return (await this._batchExecuteServerRequestAsync( transaction, makerAddress, - feeRecipientAddress, - )) as CoordinatorServerCancellationResponse; + endpoints, + )) as CoordinatorServerCancellationResponse[]; } /** - * Hard cancellation on Exchange contract. Cancels a single order. + * Cancels an order on-chain and involves an Ethereum transaction. * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. @@ -411,8 +442,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('makerAddress', order.makerAddress, this._web3Wrapper); const data = this._transactionEncoder.cancelOrderTx(order); - const transaction = await this._toSignedZeroExTransactionAsync(data, order.makerAddress); - return this._sendTransactionAsync( + const transaction = await this._generateSignedZeroExTransactionAsync(data, order.makerAddress); + return this._submitCoordinatorTransactionAsync( transaction, order.makerAddress, transaction.signature, @@ -423,8 +454,8 @@ export class CoordinatorWrapper extends ContractWrapper { } /** - * Hard cancellation on Exchange contract. - * Batch version of cancelOrderAsync. Executes multiple cancels atomically in a single transaction. + * Batch version of hardCancelOrderAsync. Cancels orders on-chain and involves an Ethereum transaction. + * Executes multiple cancels atomically in a single transaction. * @param orders An array of orders to cancel. * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. @@ -440,8 +471,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); const data = this._transactionEncoder.batchCancelOrdersTx(orders); - const transaction = await this._toSignedZeroExTransactionAsync(data, makerAddress); - return this._sendTransactionAsync( + const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); + return this._submitCoordinatorTransactionAsync( transaction, makerAddress, transaction.signature, @@ -452,7 +483,7 @@ export class CoordinatorWrapper extends ContractWrapper { } /** - * Hard cancellation on Exchange contract. + * Cancels orders on-chain and involves an Ethereum transaction. * Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch * and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). * @param targetOrderEpoch Target order epoch. @@ -477,8 +508,8 @@ export class CoordinatorWrapper extends ContractWrapper { }); // // todo: find out why this doesn't work (xianny) // const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); - // const transaction = await this._toSignedZeroExTransactionAsync(data, senderAddress); - // return this._sendTransactionAsync( + // const transaction = await this._generateSignedZeroExTransactionAsync(data, senderAddress); + // return this._submitCoordinatorTransactionAsync( // transaction, // senderAddress, // transaction.signature, @@ -488,16 +519,25 @@ export class CoordinatorWrapper extends ContractWrapper { // ); } - public async assertValidCoordinatorApprovalsAsync( + /** + * Validates that the 0x transaction has been approved by all of the feeRecipients that correspond to each order in the transaction's Exchange calldata. + * Throws an error if the transaction approvals are not valid. Will not detect failures that would occur when the transaction is executed on the Exchange contract. + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this function. + * @param transactionSignature Proof that the transaction has been signed by the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata. + */ + public async assertValidCoordinatorApprovalsOrThrowAsync( transaction: ZeroExTransaction, txOrigin: string, - signature: string, + transactionSignature: string, approvalExpirationTimeSeconds: BigNumber[], approvalSignatures: string[], ): Promise { assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema); assert.isETHAddressHex('txOrigin', txOrigin); - assert.isHexString('signature', signature); + assert.isHexString('transactionSignature', transactionSignature); for (const expirationTime of approvalExpirationTimeSeconds) { assert.isBigNumber('expirationTime', expirationTime); } @@ -505,65 +545,86 @@ export class CoordinatorWrapper extends ContractWrapper { assert.isHexString('approvalSignature', approvalSignature); } - return this._contractInstance.assertValidCoordinatorApprovals.callAsync( + await this._contractInstance.assertValidCoordinatorApprovals.callAsync( transaction, txOrigin, - signature, + transactionSignature, approvalExpirationTimeSeconds, approvalSignatures, ); } + /** + * Recovers the address of a signer given a hash and signature. + * @param hash Any 32 byte hash. + * @param signature Proof that the hash has been signed by signer. + * @returns Signer address. + */ public async getSignerAddressAsync(hash: string, signature: string): Promise { assert.isHexString('hash', hash); assert.isHexString('signature', signature); - return this._contractInstance.getSignerAddress.callAsync(hash, signature); + const signerAddress = await this._contractInstance.getSignerAddress.callAsync(hash, signature); + return signerAddress; } - private async _sendTransactionAsync( - transaction: { salt: BigNumber; signerAddress: string; data: string }, - txOrigin: string, - transactionSignature: string, - approvalExpirationTimeSeconds: BigNumber[], - approvalSignatures: string[], - orderTransactionOpts: OrderTransactionOpts, + private async _handleFillsAsync( + data: string, + takerAddress: string, + feeRecipientAddresses: string[], + orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, ): Promise { - if (orderTransactionOpts.shouldValidate) { - await this._contractInstance.executeTransaction.callAsync( - transaction, - txOrigin, - transactionSignature, - approvalExpirationTimeSeconds, - approvalSignatures, - { - from: txOrigin, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - } - const txHash = await this._contractInstance.executeTransaction.sendTransactionAsync( + const uniqueFeeRecipients = [...new Set(feeRecipientAddresses)]; + const endpoints = await this._getServerEndpointsOrThrowAsync(uniqueFeeRecipients); + const transaction = await this._generateSignedZeroExTransactionAsync(data, takerAddress); + const approvalResponses = (await this._batchExecuteServerRequestAsync( transaction, - txOrigin, - transactionSignature, - approvalExpirationTimeSeconds, - approvalSignatures, - { - from: txOrigin, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, + takerAddress, + endpoints, + )) as CoordinatorServerApprovalResponse[]; + + // concatenate all approval responses + const { allSignatures, allExpirations } = approvalResponses.reduce( + (accumulator, { signatures, expirationTimeSeconds }) => { + const expirations = Array(signatures.length).fill(expirationTimeSeconds); + accumulator.allSignatures.concat(signatures); + accumulator.allExpirations.concat(expirations); + return accumulator; }, + { allSignatures: new Array(), allExpirations: new Array() }, ); - return txHash; + + // submit transaction with approvals + return this._submitCoordinatorTransactionAsync( + transaction, + takerAddress, + transaction.signature, + allSignatures, + allExpirations, + orderTransactionOpts, + ); + } + private async _getServerEndpointsOrThrowAsync(feeRecipientAddresses: string[]): Promise { + const uniqueFeeRecipients = [...new Set(feeRecipientAddresses)]; + const endpoints = uniqueFeeRecipients.map(feeRecipientAddress => { + const coordinatorOperatorEndpoint = this._registryInstance.getCoordinatorEndpoint.callAsync( + feeRecipientAddress, + ); + if (coordinatorOperatorEndpoint === undefined) { + throw new Error( + `No Coordinator server endpoint found in Coordinator Registry for feeRecipientAddress: ${feeRecipientAddress}. Registry contract address: ${ + this.registryAddress + }`, + ); + } + return coordinatorOperatorEndpoint; + }); + return Promise.all(endpoints); } - private async _toSignedZeroExTransactionAsync( + private async _generateSignedZeroExTransactionAsync( data: string, senderAddress: string, ): Promise { - await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); const normalizedSenderAddress = senderAddress.toLowerCase(); const transaction: ZeroExTransaction = { @@ -584,82 +645,93 @@ export class CoordinatorWrapper extends ContractWrapper { }; } - private async _requestServerResponseAsync( - transaction: SignedZeroExTransaction, - senderAddress: string, - feeRecipientAddress: string, + private async _executeServerRequestAsync( + signedTransaction: SignedZeroExTransaction, + txOrigin: string, + endpoint: string, ): Promise { - assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema); - assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress); - - const coordinatorOperatorEndpoint = await this._registryInstance.getCoordinatorEndpoint.callAsync( - feeRecipientAddress, - ); - if (coordinatorOperatorEndpoint === undefined) { - throw new Error( - `Could not find endpoint for coordinator operator with { coordinatorAddress: ${ - this.address - }, registryAddress: ${this.registryAddress}, operatorAddress: ${feeRecipientAddress}}`, - ); - } - const requestPayload = { - signedTransaction: transaction, - txOrigin: senderAddress, + signedTransaction, + txOrigin, }; - const response = await fetchAsync( - `${coordinatorOperatorEndpoint}/v1/request_transaction?networkId=${this.networkId}`, - { - body: JSON.stringify(requestPayload), - method: 'POST', - headers: { - 'Content-Type': 'application/json; charset=utf-8', - }, + const response = await fetchAsync(`${endpoint}/v1/request_transaction?networkId=${this.networkId}`, { + body: JSON.stringify(requestPayload), + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', }, - ); + }); if (response.status !== HTTP_OK) { - throw new Error(`${response.status}: ${JSON.stringify(await response.json())}`); // todo (xianny) + if (response.status === 400) { // tslint:disable-line:custom-no-magic-numbers + const errorReport = await response.json(); + const errorDetails = { + ...errorReport, + coordinatorOperator: endpoint, + request: requestPayload, + }; + throw new Error(JSON.stringify(errorDetails)); + } else { + throw new Error( + `Error response from coordinator operator at [${endpoint}]. Request payload: ${JSON.stringify( + requestPayload, + )}. Response: [${response.status}] ${JSON.stringify(await response.json())}`, + ); // todo (xianny) + } } - return (await response.json()) as CoordinatorServerApprovalResponse | CoordinatorServerCancellationResponse; } - private async _handleFillAsync( - data: string, - takerAddress: string, - feeRecipientAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - - const transaction = await this._toSignedZeroExTransactionAsync(data, takerAddress); - const { signatures, expirationTimeSeconds } = (await this._requestServerResponseAsync( - transaction, - takerAddress, - feeRecipientAddress, - )) as CoordinatorServerApprovalResponse; - - return this._sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [expirationTimeSeconds], - signatures, - orderTransactionOpts, - ); + private async _batchExecuteServerRequestAsync( + signedTransaction: SignedZeroExTransaction, + txOrigin: string, + endpoints: string[], + ): Promise> { + const responses = endpoints.map(endpoint => { + const response = this._executeServerRequestAsync(signedTransaction, txOrigin, endpoint); + return response; + }); + return Promise.all(responses); } -} -function getFeeRecipientOrThrow(orders: Array): string { - const uniqueFeeRecipients = new Set(orders.map(o => o.feeRecipientAddress)); - if (uniqueFeeRecipients.size > 1) { - throw new Error( - `All orders in a batch must have the same feeRecipientAddress (a valid coordinator operator address)`, + private async _submitCoordinatorTransactionAsync( + transaction: { salt: BigNumber; signerAddress: string; data: string }, + txOrigin: string, + transactionSignature: string, + approvalExpirationTimeSeconds: BigNumber[], + approvalSignatures: string[], + orderTransactionOpts: OrderTransactionOpts, + ): Promise { + if (orderTransactionOpts.shouldValidate) { + await this._contractInstance.executeTransaction.callAsync( + transaction, + txOrigin, + transactionSignature, + approvalExpirationTimeSeconds, + approvalSignatures, + { + from: txOrigin, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, + }, + ); + } + const txHash = await this._contractInstance.executeTransaction.sendTransactionAsync( + transaction, + txOrigin, + transactionSignature, + approvalExpirationTimeSeconds, + approvalSignatures, + { + from: txOrigin, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, + }, ); + return txHash; } - return orders[0].feeRecipientAddress; } function getMakerAddressOrThrow(orders: Array): string { @@ -669,4 +741,4 @@ function getMakerAddressOrThrow(orders: Array): string { } return orders[0].makerAddress; } - // tslint:disable:max-file-line-count +// tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 0d534e021a..9797ec181d 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -6,7 +6,7 @@ import { BlockchainLifecycle } from '@0x/dev-utils'; import { FillScenarios } from '@0x/fill-scenarios'; import { assetDataUtils } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; -import { BigNumber, fetchAsync } from '@0x/utils'; +import { BigNumber, fetchAsync, logUtils } from '@0x/utils'; import * as chai from 'chai'; import * as http from 'http'; import 'mocha'; @@ -21,13 +21,16 @@ import { provider, web3Wrapper } from './utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const coordinatorEndpoint = 'http://localhost:3000'; +const coordinatorPort = '3000'; +const anotherCoordinatorPort = '4000'; +const coordinatorEndpoint = 'http://localhost:'; // tslint:disable:custom-no-magic-numbers -describe('CoordinatorWrapper', () => { +describe.only('CoordinatorWrapper', () => { const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); - let app: http.Server; + let coordinatorServerApp: http.Server; + let anotherCoordinatorServerApp: http.Server; let contractWrappers: ContractWrappers; let fillScenarios: FillScenarios; let exchangeContractAddress: string; @@ -37,6 +40,7 @@ describe('CoordinatorWrapper', () => { let takerAddress: string; let feeRecipientAddress: string; let anotherFeeRecipientAddress: string; + let unknownAddress: string; let makerTokenAddress: string; let takerTokenAddress: string; let makerAssetData: string; @@ -44,6 +48,7 @@ describe('CoordinatorWrapper', () => { let txHash: string; let signedOrder: SignedOrder; let anotherSignedOrder: SignedOrder; + let signedOrderWithDifferentFeeRecipient: SignedOrder; let coordinatorRegistryInstance: CoordinatorRegistryContract; before(async () => { const contractAddresses = await migrateOnceAsync(); @@ -65,7 +70,7 @@ describe('CoordinatorWrapper', () => { contractWrappers.erc20Proxy.address, contractWrappers.erc721Proxy.address, ); - [, makerAddress, takerAddress, feeRecipientAddress, anotherFeeRecipientAddress] = userAddresses.slice(0, 5); + [, makerAddress, takerAddress, feeRecipientAddress, anotherFeeRecipientAddress, unknownAddress] = userAddresses.slice(0, 6); [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); [makerAssetData, takerAssetData] = [ assetDataUtils.encodeERC20AssetData(makerTokenAddress), @@ -74,7 +79,7 @@ describe('CoordinatorWrapper', () => { // set up mock coordinator server const coordinatorServerConfigs = { - HTTP_PORT: 3000, + HTTP_PORT: 3000, // Only used in default instantiation in 0x-coordinator-server/server.js; not used here NETWORK_ID_TO_SETTINGS: { 50: { FEE_RECIPIENTS: [ @@ -91,7 +96,7 @@ describe('CoordinatorWrapper', () => { ].toString('hex'), }, ], - // Ethereum RPC url, only used in the default instantiation in server.js of 0x-coordinator-server + // Ethereum RPC url, only used in the default instantiation in 0x-coordinator-server/server.js // Not used here when instantiating with the imported app RPC_URL: 'http://ignore', }, @@ -100,16 +105,26 @@ describe('CoordinatorWrapper', () => { SELECTIVE_DELAY_MS: 0, EXPIRATION_DURATION_SECONDS: 60, // 1 minute }; - app = await getAppAsync( + coordinatorServerApp = await getAppAsync( { [config.networkId]: provider, }, coordinatorServerConfigs, ); - await app.listen(coordinatorServerConfigs.HTTP_PORT, () => { - // tslint:disable-line:await-promise - console.log(`Coordinator SERVER API (HTTP) listening on port ${coordinatorServerConfigs.HTTP_PORT}!`); // tslint:disable-line:no-console + await coordinatorServerApp.listen(coordinatorPort, () => { + logUtils.log(`Coordinator SERVER API (HTTP) listening on port ${coordinatorPort}!`); + }); + + anotherCoordinatorServerApp = await getAppAsync( + { + [config.networkId]: provider, + }, + coordinatorServerConfigs, + ); + + await anotherCoordinatorServerApp.listen(anotherCoordinatorPort, () => { + logUtils.log(`Coordinator SERVER API (HTTP) listening on port ${anotherCoordinatorPort}!`); }); // setup coordinator registry @@ -117,15 +132,21 @@ describe('CoordinatorWrapper', () => { CoordinatorRegistry.compilerOutput.abi, contractAddresses.coordinatorRegistry, provider, - { gas: 6000000 }, ); await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync(coordinatorEndpoint, { + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync(`${coordinatorEndpoint}${coordinatorPort}`, { from: feeRecipientAddress, }), constants.AWAIT_TRANSACTION_MINED_MS, ); + + await web3Wrapper.awaitTransactionSuccessAsync( + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync(`${coordinatorEndpoint}${anotherCoordinatorPort}`, { + from: anotherFeeRecipientAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); }); after(async () => { await blockchainLifecycle.revertAsync(); @@ -152,19 +173,37 @@ describe('CoordinatorWrapper', () => { fillableAmount, feeRecipientAddress, ); + signedOrderWithDifferentFeeRecipient = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + takerAddress, + fillableAmount, + anotherFeeRecipientAddress, + ); }); afterEach(async () => { await blockchainLifecycle.revertAsync(); }); describe('test setup', () => { it('should have coordinator registry which returns an endpoint', async () => { - const recordedCoordinatorEndpoint = await coordinatorRegistryInstance.getCoordinatorEndpoint.callAsync( + const setCoordinatorEndpoint = await coordinatorRegistryInstance.getCoordinatorEndpoint.callAsync( feeRecipientAddress, ); - expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); + const anotherSetCoordinatorEndpoint = await coordinatorRegistryInstance.getCoordinatorEndpoint.callAsync( + anotherFeeRecipientAddress, + ); + expect(setCoordinatorEndpoint).to.be.equal(`${coordinatorEndpoint}${coordinatorPort}`); + expect(anotherSetCoordinatorEndpoint).to.be.equal(`${coordinatorEndpoint}${anotherCoordinatorPort}`); }); - it('should have coordinator server endpoint which responds to pings', async () => { - const result = await fetchAsync(`${coordinatorEndpoint}/v1/ping`); + it('should have coordinator server endpoints which respond to pings', async () => { + let result = await fetchAsync(`${coordinatorEndpoint}${coordinatorPort}/v1/ping`); + expect(result.status).to.be.equal(200); + expect(await result.text()).to.be.equal('pong'); + + result = await fetchAsync(`${coordinatorEndpoint}${anotherCoordinatorPort}/v1/ping`); expect(result.status).to.be.equal(200); expect(await result.text()).to.be.equal('pong'); }); @@ -213,6 +252,44 @@ describe('CoordinatorWrapper', () => { ); await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); + it.skip('should fill a batch of orders with different feeRecipientAddresses', async () => { + const signedOrders = [signedOrder, anotherSignedOrder, signedOrderWithDifferentFeeRecipient]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.coordinator.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + }); + describe('#batchFillOrdersNoThrowAsync', () => { + it('should fill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.coordinator.batchFillOrdersNoThrowAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + let orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); + orderInfo = await contractWrappers.exchange.getOrderInfoAsync(anotherSignedOrder); + expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); + }); + }); + describe('#batchFillOrKillOrdersAsync', () => { + it('should fill or kill a batch of valid orders', async () => { + const signedOrders = [signedOrder, anotherSignedOrder]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + txHash = await contractWrappers.coordinator.batchFillOrKillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); }); describe('#marketBuyOrdersAsync', () => { it('should market buy', async () => { @@ -266,85 +343,48 @@ describe('CoordinatorWrapper', () => { expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); }); }); - describe('#batchFillOrdersNoThrowAsync', () => { - it('should fill a batch of valid orders', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; - txHash = await contractWrappers.coordinator.batchFillOrdersNoThrowAsync( - signedOrders, - takerAssetFillAmounts, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - let orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - orderInfo = await contractWrappers.exchange.getOrderInfoAsync(anotherSignedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - }); - }); - describe('#batchFillOrKillOrdersAsync', () => { - it('should fill or kill a batch of valid orders', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; - txHash = await contractWrappers.coordinator.batchFillOrKillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); - describe('#matchOrdersAsync', () => { - it('should match two valid ordersr', async () => { - const matchingSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - takerAssetData, - makerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - txHash = await contractWrappers.exchange.matchOrdersAsync( - signedOrder, - matchingSignedOrder, - takerAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); }); describe('soft cancel order(s)', () => { describe('#softCancelOrderAsync', () => { - it('should cancel a valid order', async () => { + it('should soft cancel a valid order', async () => { const response = await contractWrappers.coordinator.softCancelOrderAsync(signedOrder); expect(response.outstandingFillSignatures).to.have.lengthOf(0); expect(response.cancellationSignatures).to.have.lengthOf(1); }); }); describe('#batchSoftCancelOrdersAsync', () => { - it('should cancel a batch of valid orders', async () => { + it('should soft cancel a batch of valid orders', async () => { const orders = [signedOrder, anotherSignedOrder]; const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); - expect(response.outstandingFillSignatures).to.have.lengthOf(0); - expect(response.cancellationSignatures).to.have.lengthOf(1); + expect(response).to.have.lengthOf(1); + expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(response[0].cancellationSignatures).to.have.lengthOf(1); + }); + it.skip('should soft cancel a batch of orders with different feeRecipientAddresses', async () => { + const orders = [signedOrder, anotherSignedOrder]; + const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); + expect(response).to.have.lengthOf(1); + expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(response[0].cancellationSignatures).to.have.lengthOf(1); }); }); }); describe('hard cancel order(s)', () => { describe('#hardCancelOrderAsync', () => { - it('should cancel a valid order', async () => { + it('should hard cancel a valid order', async () => { txHash = await contractWrappers.coordinator.hardCancelOrderAsync(signedOrder); await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#batchHardCancelOrdersAsync', () => { - it('should cancel a batch of valid orders', async () => { + it('should hard cancel a batch of valid orders', async () => { const orders = [signedOrder, anotherSignedOrder]; txHash = await contractWrappers.coordinator.batchHardCancelOrdersAsync(orders); await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#cancelOrdersUpTo/getOrderEpochAsync', () => { - it('should cancel orders up to target order epoch', async () => { + it('should hard cancel orders up to target order epoch', async () => { const targetOrderEpoch = new BigNumber(42); txHash = await contractWrappers.coordinator.hardCancelOrdersUpToAsync(targetOrderEpoch, makerAddress); await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); @@ -356,4 +396,28 @@ describe('CoordinatorWrapper', () => { }); }); }); + describe('coordinator edge cases', () => { + it('should throw error when feeRecipientAddress is not in registry', async () => { + const badOrder = fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + takerAddress, + fillableAmount, + unknownAddress, + ); + }); + it('should throw error when coordinator endpoint is malformed', async () => { + await web3Wrapper.awaitTransactionSuccessAsync( + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync('localhost', { + from: unknownAddress, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + + }); + + }); }); diff --git a/yarn.lock b/yarn.lock index 7a053df770..96603e8280 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1547,11 +1547,6 @@ version "3.0.0" resolved "https://registry.yarnpkg.com/@types/compare-versions/-/compare-versions-3.0.0.tgz#4a45dffe0ebbc00d0f2daef8a0e96ffc66cf5955" -"@types/cookiejar@*": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" - integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== - "@types/deep-equal@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.1.tgz#71cfabb247c22bcc16d536111f50c0ed12476b03" @@ -2007,21 +2002,6 @@ "@types/react" "*" csstype "^2.2.0" -"@types/superagent@*": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.1.tgz#61f0b43d7db93a3c286c124512b7c228183c32fa" - integrity sha512-NetXrraTWPcdGG6IwYJhJ5esUGx8AYNiozbc1ENWEsF6BsD4JmNODJczI6Rm1xFPVp6HZESds9YCfqz4zIsM6A== - dependencies: - "@types/cookiejar" "*" - "@types/node" "*" - -"@types/supertest@^2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.7.tgz#46ff6508075cd4519736be060f0d6331a5c8ca7b" - integrity sha512-GibTh4OTkal71btYe2fpZP/rVHIPnnUsYphEaoywVHo+mo2a/LhlOFkIm5wdN0H0DA0Hx8x+tKgCYMD9elHu5w== - dependencies: - "@types/superagent" "*" - "@types/tapable@*": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" @@ -4240,10 +4220,6 @@ camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -camelcase@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" - caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" @@ -4768,13 +4744,6 @@ combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5, combined- dependencies: delayed-stream "~1.0.0" -combined-stream@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== - dependencies: - delayed-stream "~1.0.0" - comma-separated-tokens@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.5.tgz#b13793131d9ea2d2431cf5b507ddec258f0ce0db" @@ -4836,11 +4805,6 @@ component-classes@^1.2.5: dependencies: component-indexof "0.0.3" -component-emitter@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -5113,7 +5077,7 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" -cookiejar@^2.1.0, cookiejar@^2.1.1: +cookiejar@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" @@ -5597,7 +5561,7 @@ decamelize-keys@^1.0.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -7668,15 +7632,6 @@ forever@^0.15.3: utile "~0.2.1" winston "~0.8.1" -form-data@^2.3.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - form-data@~2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" @@ -7701,11 +7656,6 @@ format@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" -formidable@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" - integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== - forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -11418,7 +11368,7 @@ merkle-patricia-tree@^2.3.2: rlp "^2.0.0" semaphore ">=1.0.1" -methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: +methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -11489,7 +11439,7 @@ mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" -mime@^1.2.11, mime@^1.3.4, mime@^1.4.1: +mime@^1.2.11, mime@^1.3.4: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -13716,11 +13666,6 @@ qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" -qs@^6.5.1: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -16201,30 +16146,6 @@ stylis@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/stylis/-/stylis-3.5.0.tgz#016fa239663d77f868fef5b67cf201c4b7c701e1" -superagent@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" - integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== - dependencies: - component-emitter "^1.2.0" - cookiejar "^2.1.0" - debug "^3.1.0" - extend "^3.0.0" - form-data "^2.3.1" - formidable "^1.2.0" - methods "^1.1.1" - mime "^1.4.1" - qs "^6.5.1" - readable-stream "^2.3.5" - -supertest@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" - integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== - dependencies: - methods "^1.1.2" - superagent "^3.8.3" - supports-color@4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" @@ -17021,24 +16942,6 @@ typeorm@0.2.7: yargonaut "^1.1.2" yargs "^11.1.0" -typeorm@^0.2.7: - version "0.2.11" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.11.tgz#d81a295ed822e05043f2920cd539f52a963896b0" - dependencies: - app-root-path "^2.0.1" - buffer "^5.1.0" - chalk "^2.3.2" - cli-highlight "^1.2.3" - debug "^3.1.0" - dotenv "^5.0.1" - glob "^7.1.2" - js-yaml "^3.11.0" - mkdirp "^0.5.1" - reflect-metadata "^0.1.12" - xml2js "^0.4.17" - yargonaut "^1.1.2" - yargs "^12.0.5" - types-bn@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/types-bn/-/types-bn-0.0.1.tgz#4253c7c7251b14e1d77cdca6f58800e5e2b82c4b" @@ -18564,13 +18467,6 @@ yargs-parser@10.x, yargs-parser@^10.0.0, yargs-parser@^10.1.0: dependencies: camelcase "^4.1.0" -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" @@ -18681,23 +18577,6 @@ yargs@^12.0.1: y18n "^3.2.1 || ^4.0.0" yargs-parser "^10.1.0" -yargs@^12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - yargs@^3.7.2: version "3.32.0" resolved "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" From 182f698eed9e45335aafbf90a8aaef378e28f721 Mon Sep 17 00:00:00 2001 From: xianny Date: Tue, 30 Apr 2019 16:36:28 -0700 Subject: [PATCH 05/53] add better errors and fix cancelOrdersUpTo --- packages/contract-wrappers/package.json | 2 +- .../contract_wrappers/coordinator_wrapper.ts | 353 ++++++++++++------ packages/contract-wrappers/src/types.ts | 26 +- .../test/coordinator_wrapper_test.ts | 231 +++++++++--- 4 files changed, 442 insertions(+), 170 deletions(-) diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 85f3c7f6e4..030a6705eb 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -39,7 +39,7 @@ }, "devDependencies": { "@0x/contracts-test-utils": "^3.1.2", - "@0x/coordinator-server": "^0.0.6", + "@0x/coordinator-server": "0.1.0", "@0x/dev-utils": "^2.2.1", "@0x/fill-scenarios": "^3.0.5", "@0x/migrations": "^4.1.1", diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 45d12d3604..04911be689 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -10,8 +10,11 @@ import { ContractAbi } from 'ethereum-types'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; import { + CoordinatorError, + CoordinatorServerApprovalRawResponse, CoordinatorServerApprovalResponse, CoordinatorServerCancellationResponse, + CoordinatorServerResponse, OrderTransactionOpts, } from '../types'; import { assert } from '../utils/assert'; @@ -26,6 +29,9 @@ const HTTP_OK = 200; /** * This class includes all the functionality related to filling or cancelling orders through * the 0x V2 Coordinator smart contract. + * All logic related to filling orders is implemented in the private method `_handleFillsAsync`. + * Fill methods mirroring exchange fill method names are publicly exposed for convenience and + * to ensure type safety. */ export class CoordinatorWrapper extends ContractWrapper { public abi: ContractAbi = Coordinator.compilerOutput.abi; @@ -115,7 +121,7 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrderTx(signedOrder, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, [signedOrder.feeRecipientAddress], orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); } /** @@ -141,7 +147,7 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrderNoThrowTx(signedOrder, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, [signedOrder.feeRecipientAddress], orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); } /** @@ -168,7 +174,7 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrKillOrderTx(signedOrder, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, [signedOrder.feeRecipientAddress], orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); } /** @@ -201,9 +207,8 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.batchFillOrdersTx(signedOrders, takerAssetFillAmounts); - return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); } /** @@ -230,9 +235,8 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.batchFillOrdersNoThrowTx(signedOrders, takerAssetFillAmounts); - return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); } /** @@ -259,9 +263,8 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.batchFillOrKillOrdersTx(signedOrders, takerAssetFillAmounts); - return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); } /** @@ -292,9 +295,8 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.marketBuyOrdersTx(signedOrders, makerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); } /** @@ -326,8 +328,7 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.marketSellOrdersTx(signedOrders, takerAssetFillAmount); - const feeRecipients = signedOrders.map(o => o.feeRecipientAddress); - return this._handleFillsAsync(data, takerAddress, feeRecipients, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); } /** @@ -352,9 +353,8 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.marketBuyOrdersNoThrowTx(signedOrders, makerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); } /** @@ -379,9 +379,8 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const feeRecipientAddresses = signedOrders.map(o => o.feeRecipientAddress); const data = this._transactionEncoder.marketSellOrdersNoThrowTx(signedOrders, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, feeRecipientAddresses, orderTransactionOpts); + return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); } /** @@ -397,12 +396,24 @@ export class CoordinatorWrapper extends ContractWrapper { const data = this._transactionEncoder.cancelOrderTx(order); const transaction = await this._generateSignedZeroExTransactionAsync(data, order.makerAddress); - const endpoints = await this._getServerEndpointsOrThrowAsync([order.feeRecipientAddress]); - return (await this._executeServerRequestAsync( - transaction, - order.makerAddress, - endpoints[0], - )) as CoordinatorServerCancellationResponse; + const endpoint = await this._getServerEndpointOrThrowAsync(order.feeRecipientAddress); + + const response = await this._executeServerRequestAsync(transaction, order.makerAddress, endpoint); + if (response.isError) { + const error: CoordinatorError = { + message: `Could not cancel order, see 'errors' for more info`, + cancellations: [], + errors: [ + { + ...response, + orders: [order], + }, + ], + }; + throw new Error(JSON.stringify(error)); + } else { + return response.body as CoordinatorServerCancellationResponse; + } } /** @@ -415,15 +426,68 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orders', orders, schemas.ordersSchema); const makerAddress = getMakerAddressOrThrow(orders); assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); - const data = this._transactionEncoder.batchCancelOrdersTx(orders); + + // create lookup tables to match server endpoints to orders + const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; + for (const order of orders) { + if (feeRecipientsToOrders[order.feeRecipientAddress] === undefined) { + feeRecipientsToOrders[order.feeRecipientAddress] = [] as SignedOrder[]; + } + feeRecipientsToOrders[order.feeRecipientAddress].push(order); + } + + const serverEndpointsToFeeRecipients: { [feeRecipient: string]: string[] } = {}; + for (const feeRecipient of Object.keys(feeRecipientsToOrders)) { + const endpoint = await this._getServerEndpointOrThrowAsync(feeRecipient); + if (serverEndpointsToFeeRecipients[endpoint] === undefined) { + serverEndpointsToFeeRecipients[endpoint] = []; + } + serverEndpointsToFeeRecipients[endpoint].push(feeRecipient); + } + + // make server requests + let numErrors = 0; + let errorResponses: CoordinatorServerResponse[] = []; + let successResponses: CoordinatorServerCancellationResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); - const endpoints = await this._getServerEndpointsOrThrowAsync(orders.map(o => o.feeRecipientAddress)); - return (await this._batchExecuteServerRequestAsync( - transaction, - makerAddress, - endpoints, - )) as CoordinatorServerCancellationResponse[]; + for (const endpoint of Object.keys(serverEndpointsToFeeRecipients)) { + const response = await this._executeServerRequestAsync(transaction, makerAddress, endpoint); + if (response.isError) { + errorResponses = errorResponses.concat(response); + numErrors++; + } else { + successResponses = successResponses.concat({ + ...(response.body as CoordinatorServerCancellationResponse), + }); + } + } + + // if no errors + if (numErrors === 0) { + return successResponses; + } else { + // lookup orders with errors + const errorsWithOrders = errorResponses.map(resp => { + const endpoint = resp.coordinatorOperator; + const feeRecipients: string[] = serverEndpointsToFeeRecipients[endpoint]; + const _orders = feeRecipients + .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) + .reduce((acc, val) => acc.concat(val)); + return { + ...resp, + orders: _orders, + }; + }); + + // return errors and approvals + const error: CoordinatorError = { + message: `Only some orders were successfully cancelled. For more details, see 'errors'. Successful cancellations are shown in 'cancellations'.`, + cancellations: successResponses, + errors: errorsWithOrders, + }; + throw new Error(JSON.stringify(error)); + } } /** @@ -500,23 +564,17 @@ export class CoordinatorWrapper extends ContractWrapper { assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - return this._exchangeInstance.cancelOrdersUpTo.sendTransactionAsync(targetOrderEpoch, { - from: senderAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - // // todo: find out why this doesn't work (xianny) - // const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); - // const transaction = await this._generateSignedZeroExTransactionAsync(data, senderAddress); - // return this._submitCoordinatorTransactionAsync( - // transaction, - // senderAddress, - // transaction.signature, - // [], - // [], - // orderTransactionOpts, - // ); + + const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); + const transaction = await this._generateSignedZeroExTransactionAsync(data, senderAddress); + return this._submitCoordinatorTransactionAsync( + transaction, + senderAddress, + transaction.signature, + [], + [], + orderTransactionOpts, + ); } /** @@ -570,55 +628,124 @@ export class CoordinatorWrapper extends ContractWrapper { private async _handleFillsAsync( data: string, takerAddress: string, - feeRecipientAddresses: string[], + signedOrders: SignedOrder[], orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, ): Promise { - const uniqueFeeRecipients = [...new Set(feeRecipientAddresses)]; - const endpoints = await this._getServerEndpointsOrThrowAsync(uniqueFeeRecipients); + // create lookup tables to match server endpoints to orders + const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; + for (const order of signedOrders) { + const feeRecipient = order.feeRecipientAddress; + if (feeRecipientsToOrders[feeRecipient] === undefined) { + feeRecipientsToOrders[feeRecipient] = [] as SignedOrder[]; + } + feeRecipientsToOrders[feeRecipient] = feeRecipientsToOrders[feeRecipient].concat(order); + } + + const serverEndpointsToFeeRecipients: { [feeRecipient: string]: string[] } = {}; + for (const feeRecipient of Object.keys(feeRecipientsToOrders)) { + const endpoint = await this._getServerEndpointOrThrowAsync(feeRecipient); + if (serverEndpointsToFeeRecipients[endpoint] === undefined) { + serverEndpointsToFeeRecipients[endpoint] = []; + } + serverEndpointsToFeeRecipients[endpoint] = serverEndpointsToFeeRecipients[endpoint].concat(feeRecipient); + } + + // make server requests + let numErrors = 0; + let errorResponses: CoordinatorServerResponse[] = []; + let approvalResponses: CoordinatorServerResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, takerAddress); - const approvalResponses = (await this._batchExecuteServerRequestAsync( - transaction, - takerAddress, - endpoints, - )) as CoordinatorServerApprovalResponse[]; - - // concatenate all approval responses - const { allSignatures, allExpirations } = approvalResponses.reduce( - (accumulator, { signatures, expirationTimeSeconds }) => { - const expirations = Array(signatures.length).fill(expirationTimeSeconds); - accumulator.allSignatures.concat(signatures); - accumulator.allExpirations.concat(expirations); - return accumulator; - }, - { allSignatures: new Array(), allExpirations: new Array() }, - ); + for (const endpoint of Object.keys(serverEndpointsToFeeRecipients)) { + const response = await this._executeServerRequestAsync(transaction, takerAddress, endpoint); + if (response.isError) { + errorResponses = errorResponses.concat(response); + numErrors++; + } else { + approvalResponses = approvalResponses.concat(response); + } + } - // submit transaction with approvals - return this._submitCoordinatorTransactionAsync( - transaction, - takerAddress, - transaction.signature, - allSignatures, - allExpirations, - orderTransactionOpts, - ); + // if no errors + if (numErrors === 0) { + // concatenate all approval responses + const allApprovals = approvalResponses + .map(resp => formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse)) + .reduce((previous, current) => { + previous.signatures = previous.signatures.concat(current.signatures); + previous.expirationTimeSeconds = previous.expirationTimeSeconds.concat( + current.expirationTimeSeconds, + ); + return previous; + }); + + // submit transaction with approvals + return this._submitCoordinatorTransactionAsync( + transaction, + takerAddress, + transaction.signature, + allApprovals.expirationTimeSeconds, + allApprovals.signatures, + orderTransactionOpts, + ); + } else { + // format errors and approvals + // concatenate approvals + const approvedOrders = approvalResponses + .map(resp => { + const endpoint = resp.coordinatorOperator; + const feeRecipients: string[] = serverEndpointsToFeeRecipients[endpoint]; + const orders: SignedOrder[] = feeRecipients + .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) + .reduce((acc, val) => acc.concat(val), []); + return orders; + }) + .reduce((acc, curr) => acc.concat(curr), []); + + // lookup orders with errors + const errorsWithOrders = errorResponses.map(resp => { + const endpoint = resp.coordinatorOperator; + const feeRecipients: string[] = serverEndpointsToFeeRecipients[endpoint]; + const orders: SignedOrder[] = feeRecipients + .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) + .reduce((acc, val) => acc.concat(val), []); + return { + ...resp, + orders, + }; + }); + + // return errors and approvals + const error: CoordinatorError = { + message: `Only some orders obtained approvals. Transaction has been abandoned. For more details, see 'errors'. Resolve errors or resubmit with only approved orders (a new ZeroEx Transaction will have to be signed). `, + approvedOrders, + errors: errorsWithOrders, + }; + throw new Error(JSON.stringify(error)); + } + function formatRawResponse( + rawResponse: CoordinatorServerApprovalRawResponse, + ): CoordinatorServerApprovalResponse { + return { + signatures: ([] as string[]).concat(rawResponse.signatures), + expirationTimeSeconds: ([] as BigNumber[]).concat( + Array(rawResponse.signatures.length).fill(rawResponse.expirationTimeSeconds), + ), + }; + } } - private async _getServerEndpointsOrThrowAsync(feeRecipientAddresses: string[]): Promise { - const uniqueFeeRecipients = [...new Set(feeRecipientAddresses)]; - const endpoints = uniqueFeeRecipients.map(feeRecipientAddress => { - const coordinatorOperatorEndpoint = this._registryInstance.getCoordinatorEndpoint.callAsync( - feeRecipientAddress, + + private async _getServerEndpointOrThrowAsync(feeRecipientAddress: string): Promise { + const coordinatorOperatorEndpoint = await this._registryInstance.getCoordinatorEndpoint.callAsync( + feeRecipientAddress, + ); + if (coordinatorOperatorEndpoint === '') { + throw new Error( + `No Coordinator server endpoint found in Coordinator Registry for feeRecipientAddress: ${feeRecipientAddress}. Registry contract address: ${ + this.registryAddress + }`, ); - if (coordinatorOperatorEndpoint === undefined) { - throw new Error( - `No Coordinator server endpoint found in Coordinator Registry for feeRecipientAddress: ${feeRecipientAddress}. Registry contract address: ${ - this.registryAddress - }`, - ); - } - return coordinatorOperatorEndpoint; - }); - return Promise.all(endpoints); + } + return coordinatorOperatorEndpoint; } private async _generateSignedZeroExTransactionAsync( @@ -649,7 +776,7 @@ export class CoordinatorWrapper extends ContractWrapper { signedTransaction: SignedZeroExTransaction, txOrigin: string, endpoint: string, - ): Promise { + ): Promise { const requestPayload = { signedTransaction, txOrigin, @@ -662,36 +789,24 @@ export class CoordinatorWrapper extends ContractWrapper { }, }); - if (response.status !== HTTP_OK) { - if (response.status === 400) { // tslint:disable-line:custom-no-magic-numbers - const errorReport = await response.json(); - const errorDetails = { - ...errorReport, - coordinatorOperator: endpoint, - request: requestPayload, - }; - throw new Error(JSON.stringify(errorDetails)); - } else { - throw new Error( - `Error response from coordinator operator at [${endpoint}]. Request payload: ${JSON.stringify( - requestPayload, - )}. Response: [${response.status}] ${JSON.stringify(await response.json())}`, - ); // todo (xianny) - } + const isError = response.status !== HTTP_OK; + let json; + try { + json = await response.json(); + } catch (e) { + // ignore } - return (await response.json()) as CoordinatorServerApprovalResponse | CoordinatorServerCancellationResponse; - } - private async _batchExecuteServerRequestAsync( - signedTransaction: SignedZeroExTransaction, - txOrigin: string, - endpoints: string[], - ): Promise> { - const responses = endpoints.map(endpoint => { - const response = this._executeServerRequestAsync(signedTransaction, txOrigin, endpoint); - return response; - }); - return Promise.all(responses); + const result = { + isError, + status: response.status, + body: isError ? undefined : json, + error: isError ? json : undefined, + request: requestPayload, + coordinatorOperator: endpoint, + }; + + return result; } private async _submitCoordinatorTransactionAsync( diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index b1a242bc3e..ee5f96bbe0 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -9,7 +9,7 @@ import { WETH9Events, } from '@0x/abi-gen-wrappers'; import { ContractAddresses } from '@0x/contract-addresses'; -import { AssetData, OrderState, SignedOrder } from '@0x/types'; +import { AssetData, Order, OrderState, SignedOrder, SignedZeroExTransaction } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { BlockParam, ContractEventArg, DecodedLogArgs, LogEntryEvent, LogWithDecodedArgs } from 'ethereum-types'; @@ -227,6 +227,10 @@ export interface DutchAuctionData { } export interface CoordinatorServerApprovalResponse { + signatures: string[]; + expirationTimeSeconds: BigNumber[]; +} +export interface CoordinatorServerApprovalRawResponse { signatures: string[]; expirationTimeSeconds: BigNumber; } @@ -242,3 +246,23 @@ export interface CoordinatorServerCancellationResponse { ]; cancellationSignatures: string[]; } + +export interface CoordinatorServerResponse { + isError: boolean; + status: number; + body?: CoordinatorServerCancellationResponse | CoordinatorServerApprovalRawResponse; + error?: any; + request: { + signedTransaction: SignedZeroExTransaction; + txOrigin: string; + }; + coordinatorOperator: string; + orders?: Array; +} + +export interface CoordinatorError { + message: string; + approvedOrders?: SignedOrder[]; + cancellations?: CoordinatorServerCancellationResponse[]; + errors: CoordinatorServerResponse[]; +} diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 9797ec181d..4f5ec4be59 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -1,7 +1,7 @@ import { CoordinatorRegistryContract } from '@0x/abi-gen-wrappers'; import { CoordinatorRegistry } from '@0x/contract-artifacts'; import { constants } from '@0x/contracts-test-utils'; -import { getAppAsync } from '@0x/coordinator-server'; +import { defaultOrmConfig, getAppAsync } from '@0x/coordinator-server'; import { BlockchainLifecycle } from '@0x/dev-utils'; import { FillScenarios } from '@0x/fill-scenarios'; import { assetDataUtils } from '@0x/order-utils'; @@ -12,6 +12,7 @@ import * as http from 'http'; import 'mocha'; import { ContractWrappers, OrderStatus } from '../src'; +import { CoordinatorError, CoordinatorServerCancellationResponse } from '../src/types'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; @@ -38,17 +39,20 @@ describe.only('CoordinatorWrapper', () => { let userAddresses: string[]; let makerAddress: string; let takerAddress: string; - let feeRecipientAddress: string; - let anotherFeeRecipientAddress: string; - let unknownAddress: string; + let feeRecipientAddressOne: string; + let feeRecipientAddressTwo: string; + let feeRecipientAddressThree: string; + let feeRecipientAddressFour: string; + let makerTokenAddress: string; let takerTokenAddress: string; let makerAssetData: string; let takerAssetData: string; - let txHash: string; + let txHash: string | CoordinatorError; let signedOrder: SignedOrder; let anotherSignedOrder: SignedOrder; let signedOrderWithDifferentFeeRecipient: SignedOrder; + let signedOrderWithDifferentCoordinatorOperator: SignedOrder; let coordinatorRegistryInstance: CoordinatorRegistryContract; before(async () => { const contractAddresses = await migrateOnceAsync(); @@ -70,7 +74,15 @@ describe.only('CoordinatorWrapper', () => { contractWrappers.erc20Proxy.address, contractWrappers.erc721Proxy.address, ); - [, makerAddress, takerAddress, feeRecipientAddress, anotherFeeRecipientAddress, unknownAddress] = userAddresses.slice(0, 6); + [ + , + makerAddress, + takerAddress, + feeRecipientAddressOne, + feeRecipientAddressTwo, + feeRecipientAddressThree, + feeRecipientAddressFour, + ] = userAddresses.slice(0, 7); [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); [makerAssetData, takerAssetData] = [ assetDataUtils.encodeERC20AssetData(makerTokenAddress), @@ -78,24 +90,31 @@ describe.only('CoordinatorWrapper', () => { ]; // set up mock coordinator server + const feeRecipientConfigs = [ + { + ADDRESS: feeRecipientAddressOne, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressOne)].toString( + 'hex', + ), + }, + { + ADDRESS: feeRecipientAddressTwo, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressTwo)].toString( + 'hex', + ), + }, + { + ADDRESS: feeRecipientAddressThree, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressThree)].toString( + 'hex', + ), + }, + ]; const coordinatorServerConfigs = { HTTP_PORT: 3000, // Only used in default instantiation in 0x-coordinator-server/server.js; not used here NETWORK_ID_TO_SETTINGS: { 50: { - FEE_RECIPIENTS: [ - { - ADDRESS: feeRecipientAddress, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[ - userAddresses.indexOf(feeRecipientAddress) - ].toString('hex'), - }, - { - ADDRESS: anotherFeeRecipientAddress, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[ - userAddresses.indexOf(anotherFeeRecipientAddress) - ].toString('hex'), - }, - ], + FEE_RECIPIENTS: [feeRecipientConfigs[0], feeRecipientConfigs[1]], // Ethereum RPC url, only used in the default instantiation in 0x-coordinator-server/server.js // Not used here when instantiating with the imported app RPC_URL: 'http://ignore', @@ -110,9 +129,13 @@ describe.only('CoordinatorWrapper', () => { [config.networkId]: provider, }, coordinatorServerConfigs, + { + ...defaultOrmConfig, + logging: false, + }, ); - await coordinatorServerApp.listen(coordinatorPort, () => { + coordinatorServerApp.listen(coordinatorPort, () => { logUtils.log(`Coordinator SERVER API (HTTP) listening on port ${coordinatorPort}!`); }); @@ -120,10 +143,26 @@ describe.only('CoordinatorWrapper', () => { { [config.networkId]: provider, }, - coordinatorServerConfigs, + { + ...coordinatorServerConfigs, + NETWORK_ID_TO_SETTINGS: { + 50: { + FEE_RECIPIENTS: [feeRecipientConfigs[2]], + RPC_URL: 'http://ignore', + }, + }, + }, + { + type: 'sqlite', + database: 'database.sqlite_2', + entities: defaultOrmConfig.entities, + cli: defaultOrmConfig.cli, + logging: defaultOrmConfig.logging, + synchronize: defaultOrmConfig.synchronize, + }, ); - await anotherCoordinatorServerApp.listen(anotherCoordinatorPort, () => { + anotherCoordinatorServerApp.listen(anotherCoordinatorPort, () => { logUtils.log(`Coordinator SERVER API (HTTP) listening on port ${anotherCoordinatorPort}!`); }); @@ -134,17 +173,34 @@ describe.only('CoordinatorWrapper', () => { provider, ); + // register coordinator server await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync(`${coordinatorEndpoint}${coordinatorPort}`, { - from: feeRecipientAddress, - }), + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync( + `${coordinatorEndpoint}${coordinatorPort}`, + { + from: feeRecipientAddressOne, + }, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync( + `${coordinatorEndpoint}${coordinatorPort}`, + { + from: feeRecipientAddressTwo, + }, + ), constants.AWAIT_TRANSACTION_MINED_MS, ); + // register another coordinator server await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync(`${coordinatorEndpoint}${anotherCoordinatorPort}`, { - from: anotherFeeRecipientAddress, - }), + await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync( + `${coordinatorEndpoint}${anotherCoordinatorPort}`, + { + from: feeRecipientAddressThree, + }, + ), constants.AWAIT_TRANSACTION_MINED_MS, ); }); @@ -161,7 +217,7 @@ describe.only('CoordinatorWrapper', () => { makerAddress, takerAddress, fillableAmount, - feeRecipientAddress, + feeRecipientAddressOne, ); anotherSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( makerAssetData, @@ -171,7 +227,7 @@ describe.only('CoordinatorWrapper', () => { makerAddress, takerAddress, fillableAmount, - feeRecipientAddress, + feeRecipientAddressOne, ); signedOrderWithDifferentFeeRecipient = await fillScenarios.createFillableSignedOrderWithFeesAsync( makerAssetData, @@ -181,7 +237,17 @@ describe.only('CoordinatorWrapper', () => { makerAddress, takerAddress, fillableAmount, - anotherFeeRecipientAddress, + feeRecipientAddressTwo, + ); + signedOrderWithDifferentCoordinatorOperator = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + takerAddress, + fillableAmount, + feeRecipientAddressThree, ); }); afterEach(async () => { @@ -190,10 +256,10 @@ describe.only('CoordinatorWrapper', () => { describe('test setup', () => { it('should have coordinator registry which returns an endpoint', async () => { const setCoordinatorEndpoint = await coordinatorRegistryInstance.getCoordinatorEndpoint.callAsync( - feeRecipientAddress, + feeRecipientAddressOne, ); const anotherSetCoordinatorEndpoint = await coordinatorRegistryInstance.getCoordinatorEndpoint.callAsync( - anotherFeeRecipientAddress, + feeRecipientAddressThree, ); expect(setCoordinatorEndpoint).to.be.equal(`${coordinatorEndpoint}${coordinatorPort}`); expect(anotherSetCoordinatorEndpoint).to.be.equal(`${coordinatorEndpoint}${anotherCoordinatorPort}`); @@ -216,6 +282,7 @@ describe.only('CoordinatorWrapper', () => { takerTokenFillAmount, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -226,6 +293,7 @@ describe.only('CoordinatorWrapper', () => { takerTokenFillAmount, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); @@ -238,6 +306,7 @@ describe.only('CoordinatorWrapper', () => { takerTokenFillAmount, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -250,9 +319,10 @@ describe.only('CoordinatorWrapper', () => { takerAssetFillAmounts, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); - it.skip('should fill a batch of orders with different feeRecipientAddresses', async () => { + it('should fill a batch of orders with different feeRecipientAddresses with the same coordinator server', async () => { const signedOrders = [signedOrder, anotherSignedOrder, signedOrderWithDifferentFeeRecipient]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; txHash = await contractWrappers.coordinator.batchFillOrdersAsync( @@ -260,6 +330,31 @@ describe.only('CoordinatorWrapper', () => { takerAssetFillAmounts, takerAddress, ); + + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); + // coordinator-server, as currently implemented, shares a singleton database connection across + // all instantiations. Making the request to two different mocked server endpoints still hits the + // same database and fails because of the uniqueness constraint on transactions in the database. + it.skip('should fill a batch of orders with different feeRecipientAddresses with different coordinator servers', async () => { + const signedOrders = [ + signedOrder, + anotherSignedOrder, + signedOrderWithDifferentFeeRecipient, + signedOrderWithDifferentCoordinatorOperator, + ]; + const takerAssetFillAmounts = [ + takerTokenFillAmount, + takerTokenFillAmount, + takerTokenFillAmount, + takerTokenFillAmount, + ]; + txHash = await contractWrappers.coordinator.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -272,6 +367,7 @@ describe.only('CoordinatorWrapper', () => { takerAssetFillAmounts, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); let orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); @@ -288,6 +384,7 @@ describe.only('CoordinatorWrapper', () => { takerAssetFillAmounts, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -300,6 +397,7 @@ describe.only('CoordinatorWrapper', () => { makerAssetFillAmount, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -312,6 +410,7 @@ describe.only('CoordinatorWrapper', () => { makerAssetFillAmount, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); @@ -326,6 +425,7 @@ describe.only('CoordinatorWrapper', () => { takerAssetFillAmount, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -338,6 +438,7 @@ describe.only('CoordinatorWrapper', () => { takerAssetFillAmount, takerAddress, ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); @@ -348,6 +449,7 @@ describe.only('CoordinatorWrapper', () => { describe('#softCancelOrderAsync', () => { it('should soft cancel a valid order', async () => { const response = await contractWrappers.coordinator.softCancelOrderAsync(signedOrder); + expect(response.hasOwnProperty('errors')).to.be.false(); expect(response.outstandingFillSignatures).to.have.lengthOf(0); expect(response.cancellationSignatures).to.have.lengthOf(1); }); @@ -356,16 +458,38 @@ describe.only('CoordinatorWrapper', () => { it('should soft cancel a batch of valid orders', async () => { const orders = [signedOrder, anotherSignedOrder]; const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); - expect(response).to.have.lengthOf(1); - expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(response[0].cancellationSignatures).to.have.lengthOf(1); + + expect(response.hasOwnProperty('errors')).to.be.false(); + const success = response; + expect(success).to.have.lengthOf(1); + expect(success[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(success[0].cancellationSignatures).to.have.lengthOf(1); }); - it.skip('should soft cancel a batch of orders with different feeRecipientAddresses', async () => { - const orders = [signedOrder, anotherSignedOrder]; + it('should soft cancel a batch of orders with different feeRecipientAddresses', async () => { + const orders = [signedOrder, anotherSignedOrder, signedOrderWithDifferentFeeRecipient]; const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); - expect(response).to.have.lengthOf(1); - expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(response[0].cancellationSignatures).to.have.lengthOf(1); + + expect(response.hasOwnProperty('errors')).to.be.false(); + const success = response; + expect(success).to.have.lengthOf(1); + expect(success[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(success[0].cancellationSignatures).to.have.lengthOf(2); + }); + it('should soft cancel a batch of orders with different coordinatorOperator and concatenate responses', async () => { + const orders = [ + signedOrder, + anotherSignedOrder, + signedOrderWithDifferentFeeRecipient, + signedOrderWithDifferentCoordinatorOperator, + ]; + const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); + + expect(response.hasOwnProperty('errors')).to.be.false(); + const success = response; + expect(success).to.have.lengthOf(2); + expect(success[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(success[0].cancellationSignatures).to.have.lengthOf(2); + expect(success[1].cancellationSignatures).to.have.lengthOf(1); }); }); }); @@ -373,6 +497,7 @@ describe.only('CoordinatorWrapper', () => { describe('#hardCancelOrderAsync', () => { it('should hard cancel a valid order', async () => { txHash = await contractWrappers.coordinator.hardCancelOrderAsync(signedOrder); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -380,6 +505,7 @@ describe.only('CoordinatorWrapper', () => { it('should hard cancel a batch of valid orders', async () => { const orders = [signedOrder, anotherSignedOrder]; txHash = await contractWrappers.coordinator.batchHardCancelOrdersAsync(orders); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -387,10 +513,11 @@ describe.only('CoordinatorWrapper', () => { it('should hard cancel orders up to target order epoch', async () => { const targetOrderEpoch = new BigNumber(42); txHash = await contractWrappers.coordinator.hardCancelOrdersUpToAsync(targetOrderEpoch, makerAddress); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); const orderEpoch = await contractWrappers.exchange.getOrderEpochAsync( makerAddress, - constants.NULL_ADDRESS, + contractWrappers.coordinator.address, ); expect(orderEpoch).to.be.bignumber.equal(targetOrderEpoch.plus(1)); }); @@ -398,7 +525,7 @@ describe.only('CoordinatorWrapper', () => { }); describe('coordinator edge cases', () => { it('should throw error when feeRecipientAddress is not in registry', async () => { - const badOrder = fillScenarios.createFillableSignedOrderWithFeesAsync( + const badOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( makerAssetData, takerAssetData, new BigNumber(1), @@ -406,18 +533,24 @@ describe.only('CoordinatorWrapper', () => { makerAddress, takerAddress, fillableAmount, - unknownAddress, + feeRecipientAddressFour, ); + + expect( + contractWrappers.coordinator.fillOrderAsync(badOrder, takerTokenFillAmount, takerAddress), + ).to.be.rejected(); }); it('should throw error when coordinator endpoint is malformed', async () => { await web3Wrapper.awaitTransactionSuccessAsync( await coordinatorRegistryInstance.setCoordinatorEndpoint.sendTransactionAsync('localhost', { - from: unknownAddress, + from: feeRecipientAddressFour, }), constants.AWAIT_TRANSACTION_MINED_MS, ); - + expect( + contractWrappers.coordinator.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress), + ).to.be.rejected(); }); - }); }); +// tslint:disable:max-file-line-count From 4e5f6708182cef268b216aa0bd3a7dd154a418f7 Mon Sep 17 00:00:00 2001 From: xianny Date: Tue, 30 Apr 2019 16:40:04 -0700 Subject: [PATCH 06/53] remove default param from private method --- .../src/contract_wrappers/coordinator_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 04911be689..1082defe9b 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -629,7 +629,7 @@ export class CoordinatorWrapper extends ContractWrapper { data: string, takerAddress: string, signedOrders: SignedOrder[], - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, + orderTransactionOpts: OrderTransactionOpts, ): Promise { // create lookup tables to match server endpoints to orders const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; From 164dc1344fa148e7f240bd57910fa1d69a1f25f7 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 1 May 2019 10:40:09 -0700 Subject: [PATCH 07/53] bump to clear circleci cache From f4688fa60fc5ecf05ae0eaf65ee10974d85740b6 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 2 May 2019 15:28:31 -0700 Subject: [PATCH 08/53] improve unit tests --- packages/contract-wrappers/package.json | 2 + .../contract_wrappers/coordinator_wrapper.ts | 46 +- packages/contract-wrappers/src/types.ts | 22 +- .../test/coordinator_wrapper_test.ts | 461 +++++++++++------- yarn.lock | 189 ++++++- 5 files changed, 509 insertions(+), 211 deletions(-) diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 030a6705eb..bb9e14c748 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -47,6 +47,7 @@ "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", + "@types/nock": "^10.0.1", "@types/node": "*", "@types/sinon": "^2.2.2", "@types/uuid": "^3.4.3", @@ -57,6 +58,7 @@ "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", "mocha": "^4.1.0", + "nock": "^10.0.6", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "opn-cli": "^3.1.0", diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 1082defe9b..2a7f50e2e9 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -10,10 +10,11 @@ import { ContractAbi } from 'ethereum-types'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; import { - CoordinatorError, CoordinatorServerApprovalRawResponse, CoordinatorServerApprovalResponse, CoordinatorServerCancellationResponse, + CoordinatorServerError, + CoordinatorServerErrorMsg, CoordinatorServerResponse, OrderTransactionOpts, } from '../types'; @@ -388,7 +389,6 @@ export class CoordinatorWrapper extends ContractWrapper { * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). */ - @decorators.asyncZeroExErrorHandler public async softCancelOrderAsync(order: Order | SignedOrder): Promise { assert.doesConformToSchema('order', order, schemas.orderSchema); assert.isETHAddressHex('feeRecipientAddress', order.feeRecipientAddress); @@ -400,17 +400,17 @@ export class CoordinatorWrapper extends ContractWrapper { const response = await this._executeServerRequestAsync(transaction, order.makerAddress, endpoint); if (response.isError) { - const error: CoordinatorError = { - message: `Could not cancel order, see 'errors' for more info`, - cancellations: [], - errors: [ + throw new CoordinatorServerError( + CoordinatorServerErrorMsg.CancellationFailed, + [], + [], + [ { ...response, orders: [order], }, ], - }; - throw new Error(JSON.stringify(error)); + ); } else { return response.body as CoordinatorServerCancellationResponse; } @@ -421,7 +421,6 @@ export class CoordinatorWrapper extends ContractWrapper { * @param orders An array of orders to cancel. * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). */ - @decorators.asyncZeroExErrorHandler public async batchSoftCancelOrdersAsync(orders: SignedOrder[]): Promise { assert.doesConformToSchema('orders', orders, schemas.ordersSchema); const makerAddress = getMakerAddressOrThrow(orders); @@ -457,9 +456,9 @@ export class CoordinatorWrapper extends ContractWrapper { errorResponses = errorResponses.concat(response); numErrors++; } else { - successResponses = successResponses.concat({ - ...(response.body as CoordinatorServerCancellationResponse), - }); + + + successResponses = successResponses.concat(response.body as CoordinatorServerCancellationResponse); } } @@ -481,12 +480,12 @@ export class CoordinatorWrapper extends ContractWrapper { }); // return errors and approvals - const error: CoordinatorError = { - message: `Only some orders were successfully cancelled. For more details, see 'errors'. Successful cancellations are shown in 'cancellations'.`, - cancellations: successResponses, - errors: errorsWithOrders, - }; - throw new Error(JSON.stringify(error)); + throw new CoordinatorServerError( + CoordinatorServerErrorMsg.CancellationFailed, + [], + successResponses, + errorsWithOrders, + ); } } @@ -715,12 +714,12 @@ export class CoordinatorWrapper extends ContractWrapper { }); // return errors and approvals - const error: CoordinatorError = { - message: `Only some orders obtained approvals. Transaction has been abandoned. For more details, see 'errors'. Resolve errors or resubmit with only approved orders (a new ZeroEx Transaction will have to be signed). `, + throw new CoordinatorServerError( + CoordinatorServerErrorMsg.FillFailed, approvedOrders, - errors: errorsWithOrders, - }; - throw new Error(JSON.stringify(error)); + [], + errorsWithOrders, + ); } function formatRawResponse( rawResponse: CoordinatorServerApprovalRawResponse, @@ -790,6 +789,7 @@ export class CoordinatorWrapper extends ContractWrapper { }); const isError = response.status !== HTTP_OK; + let json; try { json = await response.json(); diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index ee5f96bbe0..7278a8b75e 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -260,9 +260,21 @@ export interface CoordinatorServerResponse { orders?: Array; } -export interface CoordinatorError { - message: string; - approvedOrders?: SignedOrder[]; - cancellations?: CoordinatorServerCancellationResponse[]; - errors: CoordinatorServerResponse[]; +export class CoordinatorServerError extends Error { + public message: CoordinatorServerErrorMsg; + public approvedOrders?: SignedOrder[] = []; + public cancellations?: CoordinatorServerCancellationResponse[] = []; + public errors: CoordinatorServerResponse[]; + constructor(message: CoordinatorServerErrorMsg, approvedOrders: SignedOrder[], cancellations: CoordinatorServerCancellationResponse[], errors: CoordinatorServerResponse[]) { + super(); + this.message = message; + this.approvedOrders = approvedOrders; + this.cancellations = cancellations; + this.errors = errors; + } +} + +export enum CoordinatorServerErrorMsg { + CancellationFailed = 'Failed to cancel with some coordinator server(s). See errors for more info. See cancellations for successful cancellations.', + FillFailed = 'Failed to obtain approval signatures from some coordinator server(s). See errors for more info. Current transaction has been abandoned but you may resubmit with only approvedOrders (a new ZeroEx transaction will have to be signed).', } diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 4f5ec4be59..40881dd92f 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -10,9 +10,10 @@ import { BigNumber, fetchAsync, logUtils } from '@0x/utils'; import * as chai from 'chai'; import * as http from 'http'; import 'mocha'; +import * as nock from 'nock'; -import { ContractWrappers, OrderStatus } from '../src'; -import { CoordinatorError, CoordinatorServerCancellationResponse } from '../src/types'; +import { ContractWrappers } from '../src'; +import { CoordinatorServerApprovalRawResponse, CoordinatorServerCancellationResponse, CoordinatorServerError, CoordinatorServerErrorMsg } from '../src/types'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; @@ -27,7 +28,7 @@ const anotherCoordinatorPort = '4000'; const coordinatorEndpoint = 'http://localhost:'; // tslint:disable:custom-no-magic-numbers -describe.only('CoordinatorWrapper', () => { +describe('CoordinatorWrapper', () => { const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); let coordinatorServerApp: http.Server; @@ -48,12 +49,21 @@ describe.only('CoordinatorWrapper', () => { let takerTokenAddress: string; let makerAssetData: string; let takerAssetData: string; - let txHash: string | CoordinatorError; + let txHash: string; let signedOrder: SignedOrder; let anotherSignedOrder: SignedOrder; let signedOrderWithDifferentFeeRecipient: SignedOrder; let signedOrderWithDifferentCoordinatorOperator: SignedOrder; let coordinatorRegistryInstance: CoordinatorRegistryContract; + + // for testing server error responses + let serverInternalError: any; + let serverValidationError: any; + let serverCancellationSuccess: any; + let serverApprovalSuccess: any; + let expectedCancellationError: any; + let expectedSuccessError: any; + before(async () => { const contractAddresses = await migrateOnceAsync(); await blockchainLifecycle.startAsync(); @@ -90,31 +100,30 @@ describe.only('CoordinatorWrapper', () => { ]; // set up mock coordinator server - const feeRecipientConfigs = [ - { - ADDRESS: feeRecipientAddressOne, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressOne)].toString( - 'hex', - ), - }, - { - ADDRESS: feeRecipientAddressTwo, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressTwo)].toString( - 'hex', - ), - }, - { - ADDRESS: feeRecipientAddressThree, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressThree)].toString( - 'hex', - ), - }, - ]; const coordinatorServerConfigs = { HTTP_PORT: 3000, // Only used in default instantiation in 0x-coordinator-server/server.js; not used here NETWORK_ID_TO_SETTINGS: { 50: { - FEE_RECIPIENTS: [feeRecipientConfigs[0], feeRecipientConfigs[1]], + FEE_RECIPIENTS: [ + { + ADDRESS: feeRecipientAddressOne, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressOne)].toString( + 'hex', + ), + }, + { + ADDRESS: feeRecipientAddressTwo, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressTwo)].toString( + 'hex', + ), + }, + { + ADDRESS: feeRecipientAddressThree, + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressThree)].toString( + 'hex', + ), + }, + ], // Ethereum RPC url, only used in the default instantiation in 0x-coordinator-server/server.js // Not used here when instantiating with the imported app RPC_URL: 'http://ignore', @@ -129,10 +138,7 @@ describe.only('CoordinatorWrapper', () => { [config.networkId]: provider, }, coordinatorServerConfigs, - { - ...defaultOrmConfig, - logging: false, - }, + defaultOrmConfig, ); coordinatorServerApp.listen(coordinatorPort, () => { @@ -143,15 +149,7 @@ describe.only('CoordinatorWrapper', () => { { [config.networkId]: provider, }, - { - ...coordinatorServerConfigs, - NETWORK_ID_TO_SETTINGS: { - 50: { - FEE_RECIPIENTS: [feeRecipientConfigs[2]], - RPC_URL: 'http://ignore', - }, - }, - }, + coordinatorServerConfigs, { type: 'sqlite', database: 'database.sqlite_2', @@ -274,6 +272,7 @@ describe.only('CoordinatorWrapper', () => { expect(await result.text()).to.be.equal('pong'); }); }); + // fill handling is the same for all fill methods so we can test them all through the fillOrder and batchFillOrders interfaces describe('fill order(s)', () => { describe('#fillOrderAsync', () => { it('should fill a valid order', async () => { @@ -286,30 +285,6 @@ describe.only('CoordinatorWrapper', () => { await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); - describe('#fillOrderNoThrowAsync', () => { - it('should fill a valid order', async () => { - txHash = await contractWrappers.coordinator.fillOrderNoThrowAsync( - signedOrder, - takerTokenFillAmount, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - }); - }); - describe('#fillOrKillOrderAsync', () => { - it('should fill or kill a valid order', async () => { - txHash = await contractWrappers.coordinator.fillOrKillOrderAsync( - signedOrder, - takerTokenFillAmount, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); describe('#batchFillOrdersAsync', () => { it('should fill a batch of valid orders', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; @@ -358,98 +333,11 @@ describe.only('CoordinatorWrapper', () => { await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); - describe('#batchFillOrdersNoThrowAsync', () => { - it('should fill a batch of valid orders', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; - txHash = await contractWrappers.coordinator.batchFillOrdersNoThrowAsync( - signedOrders, - takerAssetFillAmounts, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - let orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - orderInfo = await contractWrappers.exchange.getOrderInfoAsync(anotherSignedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - }); - }); - describe('#batchFillOrKillOrdersAsync', () => { - it('should fill or kill a batch of valid orders', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; - txHash = await contractWrappers.coordinator.batchFillOrKillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); - describe('#marketBuyOrdersAsync', () => { - it('should market buy', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const makerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.coordinator.marketBuyOrdersAsync( - signedOrders, - makerAssetFillAmount, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); - describe('#marketBuyOrdersNoThrowAsync', () => { - it('should no throw market buy', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const makerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.coordinator.marketBuyOrdersNoThrowAsync( - signedOrders, - makerAssetFillAmount, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - }); - }); - describe('#marketSellOrdersAsync', () => { - it('should market sell', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.coordinator.marketSellOrdersAsync( - signedOrders, - takerAssetFillAmount, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - }); - describe('#marketSellOrdersNoThrowAsync', () => { - it('should no throw market sell', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.coordinator.marketSellOrdersNoThrowAsync( - signedOrders, - takerAssetFillAmount, - takerAddress, - ); - - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); - expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - }); - }); }); describe('soft cancel order(s)', () => { describe('#softCancelOrderAsync', () => { it('should soft cancel a valid order', async () => { const response = await contractWrappers.coordinator.softCancelOrderAsync(signedOrder); - expect(response.hasOwnProperty('errors')).to.be.false(); expect(response.outstandingFillSignatures).to.have.lengthOf(0); expect(response.cancellationSignatures).to.have.lengthOf(1); }); @@ -458,22 +346,16 @@ describe.only('CoordinatorWrapper', () => { it('should soft cancel a batch of valid orders', async () => { const orders = [signedOrder, anotherSignedOrder]; const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); - - expect(response.hasOwnProperty('errors')).to.be.false(); - const success = response; - expect(success).to.have.lengthOf(1); - expect(success[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(success[0].cancellationSignatures).to.have.lengthOf(1); + expect(response).to.have.lengthOf(1); + expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(response[0].cancellationSignatures).to.have.lengthOf(1); }); it('should soft cancel a batch of orders with different feeRecipientAddresses', async () => { const orders = [signedOrder, anotherSignedOrder, signedOrderWithDifferentFeeRecipient]; const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); - - expect(response.hasOwnProperty('errors')).to.be.false(); - const success = response; - expect(success).to.have.lengthOf(1); - expect(success[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(success[0].cancellationSignatures).to.have.lengthOf(2); + expect(response).to.have.lengthOf(1); + expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(response[0].cancellationSignatures).to.have.lengthOf(2); }); it('should soft cancel a batch of orders with different coordinatorOperator and concatenate responses', async () => { const orders = [ @@ -483,13 +365,10 @@ describe.only('CoordinatorWrapper', () => { signedOrderWithDifferentCoordinatorOperator, ]; const response = await contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders); - - expect(response.hasOwnProperty('errors')).to.be.false(); - const success = response; - expect(success).to.have.lengthOf(2); - expect(success[0].outstandingFillSignatures).to.have.lengthOf(0); - expect(success[0].cancellationSignatures).to.have.lengthOf(2); - expect(success[1].cancellationSignatures).to.have.lengthOf(1); + expect(response).to.have.lengthOf(2); + expect(response[0].outstandingFillSignatures).to.have.lengthOf(0); + expect(response[0].cancellationSignatures).to.have.lengthOf(3); + expect(response[1].cancellationSignatures).to.have.lengthOf(3); // both coordinator servers support the same feeRecipients }); }); }); @@ -497,7 +376,6 @@ describe.only('CoordinatorWrapper', () => { describe('#hardCancelOrderAsync', () => { it('should hard cancel a valid order', async () => { txHash = await contractWrappers.coordinator.hardCancelOrderAsync(signedOrder); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -505,7 +383,6 @@ describe.only('CoordinatorWrapper', () => { it('should hard cancel a batch of valid orders', async () => { const orders = [signedOrder, anotherSignedOrder]; txHash = await contractWrappers.coordinator.batchHardCancelOrdersAsync(orders); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); @@ -552,5 +429,249 @@ describe.only('CoordinatorWrapper', () => { ).to.be.rejected(); }); }); + describe('coordinator server errors', () => { + beforeEach('setup', () => { + serverValidationError = {'code': 100, 'reason': 'Validation Failed', 'validationErrors': [{'field': 'signedTransaction', 'code': 1011, 'reason': 'A transaction can only be approved once. To request approval to perform the same actions, generate and sign an identical transaction with a different salt value.'}]}; + serverInternalError = {}; + serverCancellationSuccess = { + 'outstandingFillSignatures': [ + { + 'orderHash': '0xd1dc61f3e7e5f41d72beae7863487beea108971de678ca00d903756f842ef3ce', + 'approvalSignatures': [ + '0x1c7383ca8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a8a535671303', + ], + 'expirationTimeSeconds': 1552390380, + 'takerAssetFillAmount': 100000000000000000000, + }, + ], + 'cancellationSignatures': [ + '0x2ea3117a8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a855b5a7b401', + ], + }; + serverApprovalSuccess = { + 'signatures': [ + '0x1cc07d7ae39679690a91418d46491520f058e4fb14debdf2e98f2376b3970de8512ace44af0be6d1c65617f7aae8c2364ff63f241515ee1559c3eeecb0f671d9e903', + ], + 'expirationTimeSeconds': 1552390014, + }; + + nock(`${coordinatorEndpoint}${coordinatorPort}`) + .post('/v1/request_transaction', () => true) + .query({ + networkId: 50, + }) + .reply(400, serverValidationError); + }); + it('should throw error when softCancel fails', done => { + contractWrappers.coordinator.softCancelOrderAsync(signedOrder) + .then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done() + }); + + }); + it('should throw error when batch soft cancel fails with single coordinator operator', done => { + const orders = [signedOrder, signedOrderWithDifferentFeeRecipient]; + contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders) + .then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal(orders); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done() + }); + }); + it('should throw consolidated error when batch soft cancel partially fails with different coordinator operators', done => { + nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) + .post('/v1/request_transaction', () => true) + .query({ + networkId: 50, + }) + .reply(200, serverCancellationSuccess); + + const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; + contractWrappers.coordinator.batchSoftCancelOrdersAsync( + signedOrders, + ).then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.deep.equal([serverCancellationSuccess]); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done(); + }); + + }); + it('should throw consolidated error when batch soft cancel totally fails with different coordinator operators', done => { + nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) + .post('/v1/request_transaction', () => true) + .query({ + networkId: 50, + }) + .reply(400, serverValidationError); + + const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; + contractWrappers.coordinator.batchSoftCancelOrdersAsync(signedOrders) + .then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + + const anotherErrorBody = err.errors[1]; + expect(anotherErrorBody.isError).to.be.true(); + expect(anotherErrorBody.status).to.equal(400); + expect(anotherErrorBody.error).to.deep.equal(serverValidationError); + expect(anotherErrorBody.orders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); + expect(anotherErrorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${anotherCoordinatorPort}`); + done() + }); + + }); + it('should throw error when a fill fails', done => { + contractWrappers.coordinator.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress) + .then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done() + }); + + }); + it('should throw error when batch fill fails with single coordinator operator', done => { + const signedOrders = [signedOrder, signedOrderWithDifferentFeeRecipient]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; + contractWrappers.coordinator.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ).then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal(signedOrders); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done() + }); + + }); + it('should throw consolidated error when batch fill partially fails with different coordinator operators', done => { + nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) + .post('/v1/request_transaction', () => true) + .query({ + networkId: 50, + }) + .reply(200, serverApprovalSuccess); + + const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; + contractWrappers.coordinator.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ).then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done() + }); + }); + it('should throw consolidated error when batch fill totally fails with different coordinator operators', done => { + nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) + .post('/v1/request_transaction', () => true) + .query({ + networkId: 50, + }) + .reply(400, serverValidationError); + + const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; + const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; + contractWrappers.coordinator.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ).then(res => { + expect(res).to.be.undefined(); + }).catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + + const anotherErrorBody = err.errors[1]; + expect(anotherErrorBody.isError).to.be.true(); + expect(anotherErrorBody.status).to.equal(400); + expect(anotherErrorBody.error).to.deep.equal(serverValidationError); + expect(anotherErrorBody.orders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); + expect(anotherErrorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${anotherCoordinatorPort}`); + done() + }); + }); + }); }); // tslint:disable:max-file-line-count diff --git a/yarn.lock b/yarn.lock index 96603e8280..12a646e4cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -661,10 +661,10 @@ ethereumjs-util "^5.1.1" lodash "^4.17.11" -"@0x/coordinator-server@^0.0.6": - version "0.0.6" - resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-0.0.6.tgz#8a8544037b4275d3a39d0d4698fc10e792fc945e" - integrity sha512-i4FamF4ZW5HkgrLakN3XI3AqGLKCq0H+dC9tqg5Wf1EeFQNU5r/R8matx7hTav8SW98Fys8qG9c5NFqPcCmljg== +"@0x/coordinator-server@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-0.1.0.tgz#1b955b03760657c3d9082cc82be641d35a07d064" + integrity sha512-YsCWb/eJ11NZIFxJAdXrRhPIseAxoHUf68rXSHmqcZhth28SX0tkZOcH3dlKNfE7eGTgpbircti7C+CfxXo3/g== dependencies: "@0x/assert" "^2.0.8" "@0x/asset-buyer" "^6.0.5" @@ -1745,6 +1745,13 @@ version "2.2.48" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.48.tgz#3523b126a0b049482e1c3c11877460f76622ffab" +"@types/nock@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@types/nock/-/nock-10.0.1.tgz#ca545bdd0c2559fe76e3cda1ba011a74fb940d45" + integrity sha512-3Dbkj/f0HxuvyYfInbQCHLASFyjnNUcidabwrbhJDMZOXXznNyQpzsBgZnY2K+c43OekqWvZ+tDjGsGTKm1d5g== + dependencies: + "@types/node" "*" + "@types/node@*", "@types/node@^10.3.2": version "10.9.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.4.tgz#0f4cb2dc7c1de6096055357f70179043c33e9897" @@ -2629,7 +2636,7 @@ assert@^1.1.1: dependencies: util "0.10.3" -assertion-error@^1.0.1: +assertion-error@^1.0.1, assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -4220,6 +4227,11 @@ camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" @@ -4283,6 +4295,18 @@ chai@^4.0.1: pathval "^1.0.0" type-detect "^4.0.0" +chai@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + chain-function@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" @@ -4313,6 +4337,15 @@ chalk@^2.4.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + change-case@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.0.2.tgz#fd48746cce02f03f0a672577d1d3a8dc2eceb037" @@ -4534,6 +4567,17 @@ cli-highlight@^1.2.3: parse5 "^3.0.3" yargs "^10.0.3" +cli-highlight@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.0.tgz#1e2e6770b6c3d72c4c7d4e5ea27c496f82ec2c67" + integrity sha512-DxaFAFBGRaB+xueXP7jlJC5f867gZUZXz74RaxeZ9juEZM2Sm/s6ilzpz0uxKiT+Mj6TzHlibtXfG/dK5bSwDA== + dependencies: + chalk "^2.3.0" + highlight.js "^9.6.0" + mz "^2.4.0" + parse5 "^4.0.0" + yargs "^11.0.0" + cli-spinners@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" @@ -5538,7 +5582,7 @@ debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" dependencies: @@ -5561,7 +5605,7 @@ decamelize-keys@^1.0.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2: +decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -5637,13 +5681,13 @@ dedent@^0.7.0: version "0.7.0" resolved "http://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" -deep-eql@^3.0.0: +deep-eql@^3.0.0, deep-eql@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" dependencies: type-detect "^4.0.0" -deep-equal@*, deep-equal@^1.0.1, deep-equal@~1.0.1: +deep-equal@*, deep-equal@^1.0.0, deep-equal@^1.0.1, deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -6077,6 +6121,11 @@ dotenv@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" +dotenv@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" + integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w== + drbg.js@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" @@ -7875,6 +7924,11 @@ get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" @@ -8252,11 +8306,23 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@4.1.15, graceful-fs@^3.0.0, graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~1.2.0: +graceful-fs@^3.0.0: + version "3.0.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + integrity sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg= + dependencies: + natives "^1.1.0" + +graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +graceful-fs@~1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" + integrity sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q= + "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -10030,6 +10096,14 @@ js-yaml@^3.12.0, js-yaml@^3.9.0: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@~3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" @@ -11717,6 +11791,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natives@^1.1.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.6.tgz#a603b4a498ab77173612b9ea1acdec4d980f00bb" + integrity sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -11789,6 +11868,21 @@ no-case@^2.2.0, no-case@^2.3.2: dependencies: lower-case "^1.1.1" +nock@^10.0.6: + version "10.0.6" + resolved "https://registry.yarnpkg.com/nock/-/nock-10.0.6.tgz#e6d90ee7a68b8cfc2ab7f6127e7d99aa7d13d111" + integrity sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w== + dependencies: + chai "^4.1.2" + debug "^4.1.0" + deep-equal "^1.0.0" + json-stringify-safe "^5.0.1" + lodash "^4.17.5" + mkdirp "^0.5.0" + propagate "^1.0.0" + qs "^6.5.1" + semver "^5.5.0" + node-abi@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.3.0.tgz#f3d554d6ac72a9ee16f0f4dc9548db7c08de4986" @@ -12497,6 +12591,15 @@ os-locale@^3.0.0: lcid "^2.0.0" mem "^4.0.0" +os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -12746,7 +12849,7 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -parse5@4.0.0: +parse5@4.0.0, parse5@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -12851,7 +12954,7 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" -pathval@^1.0.0: +pathval@^1.0.0, pathval@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" @@ -13471,6 +13574,11 @@ prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, loose-envify "^1.3.1" object-assign "^4.1.1" +propagate@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-1.0.0.tgz#00c2daeedda20e87e3782b344adba1cddd6ad709" + integrity sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk= + property-information@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.0.1.tgz#c3b09f4f5750b1634c0b24205adbf78f18bdf94f" @@ -13666,6 +13774,11 @@ qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" +qs@^6.5.1: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -14468,7 +14581,7 @@ redux@^3.6.0: loose-envify "^1.1.0" symbol-observable "^1.0.3" -reflect-metadata@^0.1.10: +reflect-metadata@^0.1.10, reflect-metadata@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== @@ -14781,6 +14894,11 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + require-package-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" @@ -16942,6 +17060,26 @@ typeorm@0.2.7: yargonaut "^1.1.2" yargs "^11.1.0" +typeorm@^0.2.7: + version "0.2.17" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.17.tgz#eb98e9eeb2ce0dfc884620f49de0aeca3dc4e027" + integrity sha512-a2Yi6aG7qcSQNyYHjAZtRwhuMKt/ZPmNQg8PvpgF52Z3AgJ4LL4T5mtpfTzKgNzM4o4wP0JQcZNoGGlaRovKpw== + dependencies: + app-root-path "^2.0.1" + buffer "^5.1.0" + chalk "^2.4.2" + cli-highlight "^2.0.0" + debug "^4.1.1" + dotenv "^6.2.0" + glob "^7.1.2" + js-yaml "^3.13.1" + mkdirp "^0.5.1" + reflect-metadata "^0.1.13" + tslib "^1.9.0" + xml2js "^0.4.17" + yargonaut "^1.1.2" + yargs "^13.2.1" + types-bn@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/types-bn/-/types-bn-0.0.1.tgz#4253c7c7251b14e1d77cdca6f58800e5e2b82c4b" @@ -18467,6 +18605,14 @@ yargs-parser@10.x, yargs-parser@^10.0.0, yargs-parser@^10.1.0: dependencies: camelcase "^4.1.0" +yargs-parser@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" + integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" @@ -18577,6 +18723,23 @@ yargs@^12.0.1: y18n "^3.2.1 || ^4.0.0" yargs-parser "^10.1.0" +yargs@^13.2.1: + version "13.2.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" + integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== + dependencies: + cliui "^4.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.0.0" + yargs@^3.7.2: version "3.32.0" resolved "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" From 59b8e97ce48b244c803429d07374f10d397eb919 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 2 May 2019 15:32:00 -0700 Subject: [PATCH 09/53] lint --- .../contract_wrappers/coordinator_wrapper.ts | 2 - packages/contract-wrappers/src/types.ts | 7 +- .../test/coordinator_wrapper_test.ts | 343 +++++++++--------- 3 files changed, 185 insertions(+), 167 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 2a7f50e2e9..3cd0e3bada 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -456,8 +456,6 @@ export class CoordinatorWrapper extends ContractWrapper { errorResponses = errorResponses.concat(response); numErrors++; } else { - - successResponses = successResponses.concat(response.body as CoordinatorServerCancellationResponse); } } diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 7278a8b75e..608b59c97e 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -265,7 +265,12 @@ export class CoordinatorServerError extends Error { public approvedOrders?: SignedOrder[] = []; public cancellations?: CoordinatorServerCancellationResponse[] = []; public errors: CoordinatorServerResponse[]; - constructor(message: CoordinatorServerErrorMsg, approvedOrders: SignedOrder[], cancellations: CoordinatorServerCancellationResponse[], errors: CoordinatorServerResponse[]) { + constructor( + message: CoordinatorServerErrorMsg, + approvedOrders: SignedOrder[], + cancellations: CoordinatorServerCancellationResponse[], + errors: CoordinatorServerResponse[], + ) { super(); this.message = message; this.approvedOrders = approvedOrders; diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 40881dd92f..575755d33f 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -13,7 +13,9 @@ import 'mocha'; import * as nock from 'nock'; import { ContractWrappers } from '../src'; -import { CoordinatorServerApprovalRawResponse, CoordinatorServerCancellationResponse, CoordinatorServerError, CoordinatorServerErrorMsg } from '../src/types'; +import { + CoordinatorServerErrorMsg, +} from '../src/types'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; @@ -57,12 +59,9 @@ describe('CoordinatorWrapper', () => { let coordinatorRegistryInstance: CoordinatorRegistryContract; // for testing server error responses - let serverInternalError: any; let serverValidationError: any; let serverCancellationSuccess: any; let serverApprovalSuccess: any; - let expectedCancellationError: any; - let expectedSuccessError: any; before(async () => { const contractAddresses = await migrateOnceAsync(); @@ -107,21 +106,21 @@ describe('CoordinatorWrapper', () => { FEE_RECIPIENTS: [ { ADDRESS: feeRecipientAddressOne, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressOne)].toString( - 'hex', - ), + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[ + userAddresses.indexOf(feeRecipientAddressOne) + ].toString('hex'), }, { ADDRESS: feeRecipientAddressTwo, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressTwo)].toString( - 'hex', - ), + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[ + userAddresses.indexOf(feeRecipientAddressTwo) + ].toString('hex'), }, { ADDRESS: feeRecipientAddressThree, - PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[userAddresses.indexOf(feeRecipientAddressThree)].toString( - 'hex', - ), + PRIVATE_KEY: constants.TESTRPC_PRIVATE_KEYS[ + userAddresses.indexOf(feeRecipientAddressThree) + ].toString('hex'), }, ], // Ethereum RPC url, only used in the default instantiation in 0x-coordinator-server/server.js @@ -431,29 +430,40 @@ describe('CoordinatorWrapper', () => { }); describe('coordinator server errors', () => { beforeEach('setup', () => { - serverValidationError = {'code': 100, 'reason': 'Validation Failed', 'validationErrors': [{'field': 'signedTransaction', 'code': 1011, 'reason': 'A transaction can only be approved once. To request approval to perform the same actions, generate and sign an identical transaction with a different salt value.'}]}; + serverValidationError = { + code: 100, + reason: 'Validation Failed', + validationErrors: [ + { + field: 'signedTransaction', + code: 1011, + reason: + 'A transaction can only be approved once. To request approval to perform the same actions, generate and sign an identical transaction with a different salt value.', + }, + ], + }; serverInternalError = {}; serverCancellationSuccess = { - 'outstandingFillSignatures': [ - { - 'orderHash': '0xd1dc61f3e7e5f41d72beae7863487beea108971de678ca00d903756f842ef3ce', - 'approvalSignatures': [ - '0x1c7383ca8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a8a535671303', - ], - 'expirationTimeSeconds': 1552390380, - 'takerAssetFillAmount': 100000000000000000000, - }, + outstandingFillSignatures: [ + { + orderHash: '0xd1dc61f3e7e5f41d72beae7863487beea108971de678ca00d903756f842ef3ce', + approvalSignatures: [ + '0x1c7383ca8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a8a535671303', + ], + expirationTimeSeconds: 1552390380, + takerAssetFillAmount: 100000000000000000000, + }, ], - 'cancellationSignatures': [ - '0x2ea3117a8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a855b5a7b401', + cancellationSignatures: [ + '0x2ea3117a8ebd6de8b5b20b1c2d49bea166df7dfe4af1932c9c52ec07334e859cf2176901da35f4480ceb3ab63d8d0339d851c31929c40d88752689b9a855b5a7b401', ], - }; + }; serverApprovalSuccess = { - 'signatures': [ - '0x1cc07d7ae39679690a91418d46491520f058e4fb14debdf2e98f2376b3970de8512ace44af0be6d1c65617f7aae8c2364ff63f241515ee1559c3eeecb0f671d9e903', + signatures: [ + '0x1cc07d7ae39679690a91418d46491520f058e4fb14debdf2e98f2376b3970de8512ace44af0be6d1c65617f7aae8c2364ff63f241515ee1559c3eeecb0f671d9e903', ], - 'expirationTimeSeconds': 1552390014, - }; + expirationTimeSeconds: 1552390014, + }; nock(`${coordinatorEndpoint}${coordinatorPort}`) .post('/v1/request_transaction', () => true) @@ -463,42 +473,45 @@ describe('CoordinatorWrapper', () => { .reply(400, serverValidationError); }); it('should throw error when softCancel fails', done => { - contractWrappers.coordinator.softCancelOrderAsync(signedOrder) - .then(res => { - expect(res).to.be.undefined(); - }).catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - done() - }); + contractWrappers.coordinator + .softCancelOrderAsync(signedOrder) + .then(res => { + expect(res).to.be.undefined(); + }) + .catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done(); + }); }); it('should throw error when batch soft cancel fails with single coordinator operator', done => { const orders = [signedOrder, signedOrderWithDifferentFeeRecipient]; - contractWrappers.coordinator.batchSoftCancelOrdersAsync(orders) - .then(res => { - expect(res).to.be.undefined(); - }).catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal(orders); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - done() - }); + contractWrappers.coordinator + .batchSoftCancelOrdersAsync(orders) + .then(res => { + expect(res).to.be.undefined(); + }) + .catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal(orders); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done(); + }); }); it('should throw consolidated error when batch soft cancel partially fails with different coordinator operators', done => { nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) @@ -509,24 +522,24 @@ describe('CoordinatorWrapper', () => { .reply(200, serverCancellationSuccess); const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; - contractWrappers.coordinator.batchSoftCancelOrdersAsync( - signedOrders, - ).then(res => { - expect(res).to.be.undefined(); - }).catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.deep.equal([serverCancellationSuccess]); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - done(); - }); + contractWrappers.coordinator + .batchSoftCancelOrdersAsync(signedOrders) + .then(res => { + expect(res).to.be.undefined(); + }) + .catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.deep.equal([serverCancellationSuccess]); + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done(); + }); }); it('should throw consolidated error when batch soft cancel totally fails with different coordinator operators', done => { nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) @@ -537,10 +550,12 @@ describe('CoordinatorWrapper', () => { .reply(400, serverValidationError); const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; - contractWrappers.coordinator.batchSoftCancelOrdersAsync(signedOrders) + contractWrappers.coordinator + .batchSoftCancelOrdersAsync(signedOrders) .then(res => { expect(res).to.be.undefined(); - }).catch(err => { + }) + .catch(err => { expect(err.message).equal(CoordinatorServerErrorMsg.CancellationFailed); expect(err.approvedOrders).to.be.empty('array'); expect(err.cancellations).to.be.empty('array'); @@ -557,53 +572,53 @@ describe('CoordinatorWrapper', () => { expect(anotherErrorBody.status).to.equal(400); expect(anotherErrorBody.error).to.deep.equal(serverValidationError); expect(anotherErrorBody.orders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); - expect(anotherErrorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${anotherCoordinatorPort}`); - done() + expect(anotherErrorBody.coordinatorOperator).to.equal( + `${coordinatorEndpoint}${anotherCoordinatorPort}`, + ); + done(); }); - }); it('should throw error when a fill fails', done => { - contractWrappers.coordinator.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress) - .then(res => { - expect(res).to.be.undefined(); - }).catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - done() - }); + contractWrappers.coordinator + .fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress) + .then(res => { + expect(res).to.be.undefined(); + }) + .catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done(); + }); }); it('should throw error when batch fill fails with single coordinator operator', done => { const signedOrders = [signedOrder, signedOrderWithDifferentFeeRecipient]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; - contractWrappers.coordinator.batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - takerAddress, - ).then(res => { - expect(res).to.be.undefined(); - }).catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal(signedOrders); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - done() - }); + contractWrappers.coordinator + .batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, takerAddress) + .then(res => { + expect(res).to.be.undefined(); + }) + .catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal(signedOrders); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done(); + }); }); it('should throw consolidated error when batch fill partially fails with different coordinator operators', done => { nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) @@ -615,25 +630,24 @@ describe('CoordinatorWrapper', () => { const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; - contractWrappers.coordinator.batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - takerAddress, - ).then(res => { - expect(res).to.be.undefined(); - }).catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - done() - }); + contractWrappers.coordinator + .batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, takerAddress) + .then(res => { + expect(res).to.be.undefined(); + }) + .catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + done(); + }); }); it('should throw consolidated error when batch fill totally fails with different coordinator operators', done => { nock(`${coordinatorEndpoint}${anotherCoordinatorPort}`) @@ -645,32 +659,33 @@ describe('CoordinatorWrapper', () => { const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; - contractWrappers.coordinator.batchFillOrdersAsync( - signedOrders, - takerAssetFillAmounts, - takerAddress, - ).then(res => { - expect(res).to.be.undefined(); - }).catch(err => { - expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); - expect(err.approvedOrders).to.be.empty('array'); - expect(err.cancellations).to.be.empty('array'); - - const errorBody = err.errors[0]; - expect(errorBody.isError).to.be.true(); - expect(errorBody.status).to.equal(400); - expect(errorBody.error).to.deep.equal(serverValidationError); - expect(errorBody.orders).to.deep.equal([signedOrder]); - expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); - - const anotherErrorBody = err.errors[1]; - expect(anotherErrorBody.isError).to.be.true(); - expect(anotherErrorBody.status).to.equal(400); - expect(anotherErrorBody.error).to.deep.equal(serverValidationError); - expect(anotherErrorBody.orders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); - expect(anotherErrorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${anotherCoordinatorPort}`); - done() - }); + contractWrappers.coordinator + .batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, takerAddress) + .then(res => { + expect(res).to.be.undefined(); + }) + .catch(err => { + expect(err.message).equal(CoordinatorServerErrorMsg.FillFailed); + expect(err.approvedOrders).to.be.empty('array'); + expect(err.cancellations).to.be.empty('array'); + + const errorBody = err.errors[0]; + expect(errorBody.isError).to.be.true(); + expect(errorBody.status).to.equal(400); + expect(errorBody.error).to.deep.equal(serverValidationError); + expect(errorBody.orders).to.deep.equal([signedOrder]); + expect(errorBody.coordinatorOperator).to.equal(`${coordinatorEndpoint}${coordinatorPort}`); + + const anotherErrorBody = err.errors[1]; + expect(anotherErrorBody.isError).to.be.true(); + expect(anotherErrorBody.status).to.equal(400); + expect(anotherErrorBody.error).to.deep.equal(serverValidationError); + expect(anotherErrorBody.orders).to.deep.equal([signedOrderWithDifferentCoordinatorOperator]); + expect(anotherErrorBody.coordinatorOperator).to.equal( + `${coordinatorEndpoint}${anotherCoordinatorPort}`, + ); + done(); + }); }); }); }); From 2cf8c642990c2bb97f56960fa238f44ffce5c0b6 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 2 May 2019 15:40:19 -0700 Subject: [PATCH 10/53] remove dangling variable --- packages/contract-wrappers/test/coordinator_wrapper_test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 575755d33f..4099cb013c 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -442,7 +442,6 @@ describe('CoordinatorWrapper', () => { }, ], }; - serverInternalError = {}; serverCancellationSuccess = { outstandingFillSignatures: [ { From 5a6d0c4c0758ee47a9c1d72784431fe4b92071ac Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 2 May 2019 15:51:37 -0700 Subject: [PATCH 11/53] pin typeorm version in pipeline --- packages/pipeline/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pipeline/package.json b/packages/pipeline/package.json index 5e9188588b..dafa96c795 100644 --- a/packages/pipeline/package.json +++ b/packages/pipeline/package.json @@ -63,6 +63,6 @@ "ramda": "^0.25.0", "reflect-metadata": "^0.1.12", "sqlite3": "^4.0.2", - "typeorm": "^0.2.7" + "typeorm": "0.2.7" } } From 147644aa54635a0a39c8fabfc2df9589a1a65b6a Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 2 May 2019 17:47:17 -0700 Subject: [PATCH 12/53] prettier --- packages/contract-wrappers/test/coordinator_wrapper_test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 4099cb013c..73ae9400da 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -13,9 +13,7 @@ import 'mocha'; import * as nock from 'nock'; import { ContractWrappers } from '../src'; -import { - CoordinatorServerErrorMsg, -} from '../src/types'; +import { CoordinatorServerErrorMsg } from '../src/types'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; From f99f560db64c1bea53b6b9272dd4b322ca47764f Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 2 May 2019 18:00:01 -0700 Subject: [PATCH 13/53] add export to 0x.js --- packages/0x.js/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 6656decc7c..c08ee473d2 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -10,6 +10,7 @@ export { export { ContractWrappers, + CoordinatorWrapper, DutchAuctionWrapper, ERC20TokenWrapper, ERC721TokenWrapper, From 09daaf485d2b72c714fd24ae5ca67d3e4d1a8b7a Mon Sep 17 00:00:00 2001 From: xianny Date: Fri, 3 May 2019 12:36:47 -0700 Subject: [PATCH 14/53] more exports; upgrade coordinator server --- packages/0x.js/src/index.ts | 2 + packages/contract-wrappers/package.json | 2 +- yarn.lock | 156 +----------------------- 3 files changed, 8 insertions(+), 152 deletions(-) diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index c08ee473d2..3b7e0591a2 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -11,6 +11,8 @@ export { export { ContractWrappers, CoordinatorWrapper, + CoordinatorServerCancellationResponse, + CoordinatorServerError, DutchAuctionWrapper, ERC20TokenWrapper, ERC721TokenWrapper, diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index bb9e14c748..c9c4e103fc 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -39,7 +39,7 @@ }, "devDependencies": { "@0x/contracts-test-utils": "^3.1.2", - "@0x/coordinator-server": "0.1.0", + "@0x/coordinator-server": "0.1.1", "@0x/dev-utils": "^2.2.1", "@0x/fill-scenarios": "^3.0.5", "@0x/migrations": "^4.1.1", diff --git a/yarn.lock b/yarn.lock index 12a646e4cc..5a56633e38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -529,20 +529,6 @@ ethereum-types "^2.1.0" lodash "^4.17.11" -"@0x/contracts-erc20@1.0.8": - version "1.0.8" - resolved "https://registry.npmjs.org/@0x/contracts-erc20/-/contracts-erc20-1.0.8.tgz#882f3acf1a44148800d9bef692aa377627df9ace" - dependencies: - "@0x/base-contract" "^5.0.1" - "@0x/contracts-exchange-libs" "1.0.2" - "@0x/contracts-utils" "2.0.1" - "@0x/types" "^2.1.1" - "@0x/typescript-typings" "^4.1.0" - "@0x/utils" "^4.2.1" - "@0x/web3-wrapper" "^6.0.1" - ethereum-types "^2.1.0" - lodash "^4.17.11" - "@0x/contracts-erc20@^1.0.2", "@0x/contracts-erc20@^1.0.9": version "1.0.9" resolved "https://registry.npmjs.org/@0x/contracts-erc20/-/contracts-erc20-1.0.9.tgz#366ce8222dcae5ade0ea7ca95332416a080f6abf" @@ -557,19 +543,6 @@ ethereum-types "^2.1.0" lodash "^4.17.11" -"@0x/contracts-erc721@1.0.8": - version "1.0.8" - resolved "https://registry.npmjs.org/@0x/contracts-erc721/-/contracts-erc721-1.0.8.tgz#d3746c26eec57662654557121601b5bb81085637" - dependencies: - "@0x/base-contract" "^5.0.1" - "@0x/contracts-utils" "2.0.1" - "@0x/types" "^2.1.1" - "@0x/typescript-typings" "^4.1.0" - "@0x/utils" "^4.2.1" - "@0x/web3-wrapper" "^6.0.1" - ethereum-types "^2.1.0" - lodash "^4.17.11" - "@0x/contracts-erc721@^1.0.2", "@0x/contracts-erc721@^1.0.9": version "1.0.9" resolved "https://registry.npmjs.org/@0x/contracts-erc721/-/contracts-erc721-1.0.9.tgz#3991858a3bf5a80dcd6e5fd65e938f8adc3b347c" @@ -4227,11 +4200,6 @@ camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" @@ -4337,15 +4305,6 @@ chalk@^2.4.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - change-case@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.0.2.tgz#fd48746cce02f03f0a672577d1d3a8dc2eceb037" @@ -4567,17 +4526,6 @@ cli-highlight@^1.2.3: parse5 "^3.0.3" yargs "^10.0.3" -cli-highlight@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.0.tgz#1e2e6770b6c3d72c4c7d4e5ea27c496f82ec2c67" - integrity sha512-DxaFAFBGRaB+xueXP7jlJC5f867gZUZXz74RaxeZ9juEZM2Sm/s6ilzpz0uxKiT+Mj6TzHlibtXfG/dK5bSwDA== - dependencies: - chalk "^2.3.0" - highlight.js "^9.6.0" - mz "^2.4.0" - parse5 "^4.0.0" - yargs "^11.0.0" - cli-spinners@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" @@ -5582,7 +5530,7 @@ debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@^4.0.1, debug@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" dependencies: @@ -5605,7 +5553,7 @@ decamelize-keys@^1.0.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -6121,11 +6069,6 @@ dotenv@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" -dotenv@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" - integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w== - drbg.js@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" @@ -7924,11 +7867,6 @@ get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" -get-caller-file@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" @@ -8306,23 +8244,11 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - integrity sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg= - dependencies: - natives "^1.1.0" - -graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@4.1.15, graceful-fs@^3.0.0, graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~1.2.0: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== -graceful-fs@~1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - integrity sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q= - "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -10096,14 +10022,6 @@ js-yaml@^3.12.0, js-yaml@^3.9.0: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - js-yaml@~3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" @@ -11791,11 +11709,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -natives@^1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.6.tgz#a603b4a498ab77173612b9ea1acdec4d980f00bb" - integrity sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -12591,15 +12504,6 @@ os-locale@^3.0.0: lcid "^2.0.0" mem "^4.0.0" -os-locale@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -12849,7 +12753,7 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -parse5@4.0.0, parse5@^4.0.0: +parse5@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -14581,7 +14485,7 @@ redux@^3.6.0: loose-envify "^1.1.0" symbol-observable "^1.0.3" -reflect-metadata@^0.1.10, reflect-metadata@^0.1.13: +reflect-metadata@^0.1.10: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== @@ -14894,11 +14798,6 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - require-package-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" @@ -17060,26 +16959,6 @@ typeorm@0.2.7: yargonaut "^1.1.2" yargs "^11.1.0" -typeorm@^0.2.7: - version "0.2.17" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.17.tgz#eb98e9eeb2ce0dfc884620f49de0aeca3dc4e027" - integrity sha512-a2Yi6aG7qcSQNyYHjAZtRwhuMKt/ZPmNQg8PvpgF52Z3AgJ4LL4T5mtpfTzKgNzM4o4wP0JQcZNoGGlaRovKpw== - dependencies: - app-root-path "^2.0.1" - buffer "^5.1.0" - chalk "^2.4.2" - cli-highlight "^2.0.0" - debug "^4.1.1" - dotenv "^6.2.0" - glob "^7.1.2" - js-yaml "^3.13.1" - mkdirp "^0.5.1" - reflect-metadata "^0.1.13" - tslib "^1.9.0" - xml2js "^0.4.17" - yargonaut "^1.1.2" - yargs "^13.2.1" - types-bn@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/types-bn/-/types-bn-0.0.1.tgz#4253c7c7251b14e1d77cdca6f58800e5e2b82c4b" @@ -18605,14 +18484,6 @@ yargs-parser@10.x, yargs-parser@^10.0.0, yargs-parser@^10.1.0: dependencies: camelcase "^4.1.0" -yargs-parser@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" - integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" @@ -18723,23 +18594,6 @@ yargs@^12.0.1: y18n "^3.2.1 || ^4.0.0" yargs-parser "^10.1.0" -yargs@^13.2.1: - version "13.2.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" - integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== - dependencies: - cliui "^4.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - os-locale "^3.1.0" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.0.0" - yargs@^3.7.2: version "3.32.0" resolved "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" From 05e4b7bb362e5a38076923d2a99290a9353373ba Mon Sep 17 00:00:00 2001 From: xianny Date: Mon, 6 May 2019 21:21:30 -0700 Subject: [PATCH 15/53] WIP/broken: cannot get valid approval signatures --- packages/contract-wrappers/package.json | 1 + .../contract_wrappers/coordinator_wrapper.ts | 216 +++++++++++------- packages/contract-wrappers/src/types.ts | 58 ----- .../src/utils/coordinator_server_types.ts | 61 +++++ .../test/coordinator_wrapper_test.ts | 3 +- packages/fill-scenarios/src/fill_scenarios.ts | 6 +- yarn.lock | 32 ++- 7 files changed, 222 insertions(+), 155 deletions(-) create mode 100644 packages/contract-wrappers/src/utils/coordinator_server_types.ts diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index c9c4e103fc..7b30781da7 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -86,6 +86,7 @@ "ethereumjs-blockstream": "6.0.0", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", + "http-status-codes": "^1.3.2", "js-sha3": "^0.7.0", "lodash": "^4.17.11", "uuid": "^3.3.2" diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 3cd0e3bada..647b6c26e4 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -1,14 +1,18 @@ import { CoordinatorContract, CoordinatorRegistryContract, ExchangeContract } from '@0x/abi-gen-wrappers'; +import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import { Coordinator, CoordinatorRegistry, Exchange } from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; -import { generatePseudoRandomSalt, signatureUtils, transactionHashUtils } from '@0x/order-utils'; +import { eip712Utils, generatePseudoRandomSalt, signatureUtils, transactionHashUtils } from '@0x/order-utils'; import { Order, SignedOrder, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; -import { BigNumber, fetchAsync } from '@0x/utils'; +import { BigNumber, fetchAsync, signTypedDataUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { ContractAbi } from 'ethereum-types'; +import * as HttpStatus from 'http-status-codes'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; +import {OrderTransactionOpts} from '../types'; +import { assert } from '../utils/assert'; import { CoordinatorServerApprovalRawResponse, CoordinatorServerApprovalResponse, @@ -16,23 +20,15 @@ import { CoordinatorServerError, CoordinatorServerErrorMsg, CoordinatorServerResponse, - OrderTransactionOpts, -} from '../types'; -import { assert } from '../utils/assert'; -import { _getDefaultContractAddresses } from '../utils/contract_addresses'; +} from '../utils/coordinator_server_types'; import { decorators } from '../utils/decorators'; import { TransactionEncoder } from '../utils/transaction_encoder'; import { ContractWrapper } from './contract_wrapper'; -const HTTP_OK = 200; - /** * This class includes all the functionality related to filling or cancelling orders through - * the 0x V2 Coordinator smart contract. - * All logic related to filling orders is implemented in the private method `_handleFillsAsync`. - * Fill methods mirroring exchange fill method names are publicly exposed for convenience and - * to ensure type safety. + * the 0x V2 Coordinator extension contract. */ export class CoordinatorWrapper extends ContractWrapper { public abi: ContractAbi = Coordinator.compilerOutput.abi; @@ -65,12 +61,14 @@ export class CoordinatorWrapper extends ContractWrapper { ) { super(web3Wrapper, networkId); this.networkId = networkId; - this.address = address === undefined ? _getDefaultContractAddresses(networkId).coordinator : address; + + const contractAddresses = getContractAddressesForNetworkOrThrow(networkId); + this.address = address === undefined ? contractAddresses.coordinator : address; this.exchangeAddress = - exchangeAddress === undefined ? _getDefaultContractAddresses(networkId).coordinator : exchangeAddress; + exchangeAddress === undefined ? contractAddresses.coordinator : exchangeAddress; this.registryAddress = registryAddress === undefined - ? _getDefaultContractAddresses(networkId).coordinatorRegistry + ? contractAddresses.coordinatorRegistry : registryAddress; this._contractInstance = new CoordinatorContract( @@ -97,10 +95,10 @@ export class CoordinatorWrapper extends ContractWrapper { /** * Fills a signed order with an amount denominated in baseUnits of the taker asset. Under-the-hood, this - * method uses the `feeRecipientAddress` of the order to looks up the coordinator server endpoint registered in the + * method uses the `feeRecipientAddress` of the order to look up the coordinator server endpoint registered in the * coordinator registry contract. It requests a signature from that coordinator server before - * submitting the order and signature as a 0x transaction to the coordinator extension contract, which validates the - * signatures and then fills the order through the Exchange contract. + * submitting the order and signature as a 0x transaction to the coordinator extension contract. The coordinator extension + * contract validates signatures and then fills the order via the Exchange contract. * @param signedOrder An object that conforms to the SignedOrder interface. * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied @@ -122,7 +120,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrderTx(signedOrder, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); + return txHash; } /** @@ -148,7 +147,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrderNoThrowTx(signedOrder, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); + return txHash; } /** @@ -175,7 +175,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrKillOrderTx(signedOrder, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); + return txHash; } /** @@ -209,7 +210,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.batchFillOrdersTx(signedOrders, takerAssetFillAmounts); - return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + return txHash; } /** @@ -237,7 +239,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.batchFillOrdersNoThrowTx(signedOrders, takerAssetFillAmounts); - return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + return txHash; } /** @@ -265,7 +268,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.batchFillOrKillOrdersTx(signedOrders, takerAssetFillAmounts); - return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + return txHash; } /** @@ -297,7 +301,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.marketBuyOrdersTx(signedOrders, makerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + return txHash; } /** @@ -329,7 +334,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.marketSellOrdersTx(signedOrders, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + return txHash; } /** @@ -355,7 +361,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.marketBuyOrdersNoThrowTx(signedOrders, makerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + return txHash; } /** @@ -381,7 +388,8 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.marketSellOrdersNoThrowTx(signedOrders, takerAssetFillAmount); - return this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); + return txHash; } /** @@ -400,16 +408,19 @@ export class CoordinatorWrapper extends ContractWrapper { const response = await this._executeServerRequestAsync(transaction, order.makerAddress, endpoint); if (response.isError) { + const approvedOrders = new Array(); + const cancellations = new Array(); + const errors = [ + { + ...response, + orders: [order], + }, + ]; throw new CoordinatorServerError( CoordinatorServerErrorMsg.CancellationFailed, - [], - [], - [ - { - ...response, - orders: [order], - }, - ], + approvedOrders, + cancellations, + errors, ); } else { return response.body as CoordinatorServerCancellationResponse; @@ -447,16 +458,16 @@ export class CoordinatorWrapper extends ContractWrapper { // make server requests let numErrors = 0; - let errorResponses: CoordinatorServerResponse[] = []; - let successResponses: CoordinatorServerCancellationResponse[] = []; + const errorResponses: CoordinatorServerResponse[] = []; + const successResponses: CoordinatorServerCancellationResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); for (const endpoint of Object.keys(serverEndpointsToFeeRecipients)) { const response = await this._executeServerRequestAsync(transaction, makerAddress, endpoint); if (response.isError) { - errorResponses = errorResponses.concat(response); + errorResponses.push(response); numErrors++; } else { - successResponses = successResponses.concat(response.body as CoordinatorServerCancellationResponse); + successResponses.push(response.body as CoordinatorServerCancellationResponse); } } @@ -470,25 +481,27 @@ export class CoordinatorWrapper extends ContractWrapper { const feeRecipients: string[] = serverEndpointsToFeeRecipients[endpoint]; const _orders = feeRecipients .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) - .reduce((acc, val) => acc.concat(val)); + .reduce(flatten, []); return { ...resp, orders: _orders, }; }); + const approvedOrders = new Array(); + const cancellations = successResponses; // return errors and approvals throw new CoordinatorServerError( CoordinatorServerErrorMsg.CancellationFailed, - [], - successResponses, + approvedOrders, + cancellations, errorsWithOrders, ); } } /** - * Cancels an order on-chain and involves an Ethereum transaction. + * Cancels an order on-chain by submitting an Ethereum transaction. * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. * @param orderTransactionOpts Optional arguments this method accepts. * @return Transaction hash. @@ -504,18 +517,22 @@ export class CoordinatorWrapper extends ContractWrapper { const data = this._transactionEncoder.cancelOrderTx(order); const transaction = await this._generateSignedZeroExTransactionAsync(data, order.makerAddress); - return this._submitCoordinatorTransactionAsync( + + const approvalSignatures = new Array(); + const approvalExpirationTimeSeconds = new Array(); + const txHash = await this._submitCoordinatorTransactionAsync( transaction, order.makerAddress, transaction.signature, - [], - [], + approvalExpirationTimeSeconds, + approvalSignatures, orderTransactionOpts, ); + return txHash; } /** - * Batch version of hardCancelOrderAsync. Cancels orders on-chain and involves an Ethereum transaction. + * Batch version of hardCancelOrderAsync. Cancels orders on-chain by submitting an Ethereum transaction. * Executes multiple cancels atomically in a single transaction. * @param orders An array of orders to cancel. * @param orderTransactionOpts Optional arguments this method accepts. @@ -533,20 +550,24 @@ export class CoordinatorWrapper extends ContractWrapper { const data = this._transactionEncoder.batchCancelOrdersTx(orders); const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); - return this._submitCoordinatorTransactionAsync( + + const approvalSignatures = new Array(); + const approvalExpirationTimeSeconds = new Array(); + const txHash = await this._submitCoordinatorTransactionAsync( transaction, makerAddress, transaction.signature, - [], - [], + approvalExpirationTimeSeconds, + approvalSignatures, orderTransactionOpts, ); + return txHash; } /** - * Cancels orders on-chain and involves an Ethereum transaction. + * Cancels orders on-chain by submitting an Ethereum transaction. * Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch - * and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). + * and senderAddress equal to coordinator extension contract address. * @param targetOrderEpoch Target order epoch. * @param senderAddress Address that should send the transaction. * @param orderTransactionOpts Optional arguments this method accepts. @@ -564,14 +585,18 @@ export class CoordinatorWrapper extends ContractWrapper { const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); const transaction = await this._generateSignedZeroExTransactionAsync(data, senderAddress); - return this._submitCoordinatorTransactionAsync( + + const approvalSignatures = new Array(); + const approvalExpirationTimeSeconds = new Array(); + const txHash = await this._submitCoordinatorTransactionAsync( transaction, senderAddress, transaction.signature, - [], - [], + approvalExpirationTimeSeconds, + approvalSignatures, orderTransactionOpts, ); + return txHash; } /** @@ -628,6 +653,9 @@ export class CoordinatorWrapper extends ContractWrapper { signedOrders: SignedOrder[], orderTransactionOpts: OrderTransactionOpts, ): Promise { + + // const coordinatorOrders = signedOrders.filter(o => o.senderAddress === this.address); + // create lookup tables to match server endpoints to orders const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; for (const order of signedOrders) { @@ -635,87 +663,98 @@ export class CoordinatorWrapper extends ContractWrapper { if (feeRecipientsToOrders[feeRecipient] === undefined) { feeRecipientsToOrders[feeRecipient] = [] as SignedOrder[]; } - feeRecipientsToOrders[feeRecipient] = feeRecipientsToOrders[feeRecipient].concat(order); + feeRecipientsToOrders[feeRecipient].push(order); } - const serverEndpointsToFeeRecipients: { [feeRecipient: string]: string[] } = {}; + const serverEndpointsToFeeRecipients: { [endpoint: string]: string[] } = {}; for (const feeRecipient of Object.keys(feeRecipientsToOrders)) { const endpoint = await this._getServerEndpointOrThrowAsync(feeRecipient); if (serverEndpointsToFeeRecipients[endpoint] === undefined) { serverEndpointsToFeeRecipients[endpoint] = []; } - serverEndpointsToFeeRecipients[endpoint] = serverEndpointsToFeeRecipients[endpoint].concat(feeRecipient); + serverEndpointsToFeeRecipients[endpoint].push(feeRecipient); } // make server requests let numErrors = 0; - let errorResponses: CoordinatorServerResponse[] = []; - let approvalResponses: CoordinatorServerResponse[] = []; + const errorResponses: CoordinatorServerResponse[] = []; + const approvalResponses: CoordinatorServerResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, takerAddress); for (const endpoint of Object.keys(serverEndpointsToFeeRecipients)) { const response = await this._executeServerRequestAsync(transaction, takerAddress, endpoint); if (response.isError) { - errorResponses = errorResponses.concat(response); + errorResponses.push(response); numErrors++; } else { - approvalResponses = approvalResponses.concat(response); + approvalResponses.push(response); } } // if no errors if (numErrors === 0) { + // concatenate all approval responses const allApprovals = approvalResponses - .map(resp => formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse)) - .reduce((previous, current) => { - previous.signatures = previous.signatures.concat(current.signatures); - previous.expirationTimeSeconds = previous.expirationTimeSeconds.concat( - current.expirationTimeSeconds, - ); - return previous; - }); + .map(resp => formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse)); + console.log(JSON.stringify(allApprovals)); + const allSignatures = allApprovals.map(a => a.signatures).reduce(flatten, []); + const allExpirationTimes = allApprovals.map(a => a.expirationTimeSeconds).reduce(flatten, []); + console.log(`all signatures: ${JSON.stringify(allSignatures)}`); + console.log(allExpirationTimes); + + const typedData = eip712Utils.createCoordinatorApprovalTypedData( + transaction, + this.address, + takerAddress, + allExpirationTimes[0], + ); + const approvalHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); + const recoveredSignerAddress = await this.getSignerAddressAsync(`0x${approvalHashBuff.toString('hex')}`, allSignatures[0]); + + console.log(`recovered signer: ${recoveredSignerAddress}; feeRecipient: ${JSON.stringify(Object.keys(feeRecipientsToOrders))}`); // submit transaction with approvals - return this._submitCoordinatorTransactionAsync( + const txHash = await this._submitCoordinatorTransactionAsync( transaction, takerAddress, transaction.signature, - allApprovals.expirationTimeSeconds, - allApprovals.signatures, + allExpirationTimes, + allSignatures, orderTransactionOpts, ); + return txHash; } else { // format errors and approvals // concatenate approvals const approvedOrders = approvalResponses .map(resp => { const endpoint = resp.coordinatorOperator; - const feeRecipients: string[] = serverEndpointsToFeeRecipients[endpoint]; - const orders: SignedOrder[] = feeRecipients + const feeRecipients = serverEndpointsToFeeRecipients[endpoint]; + const orders = feeRecipients .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) - .reduce((acc, val) => acc.concat(val), []); + .reduce(flatten, []); return orders; - }) - .reduce((acc, curr) => acc.concat(curr), []); + }).reduce(flatten, []); // lookup orders with errors const errorsWithOrders = errorResponses.map(resp => { const endpoint = resp.coordinatorOperator; - const feeRecipients: string[] = serverEndpointsToFeeRecipients[endpoint]; - const orders: SignedOrder[] = feeRecipients + const feeRecipients = serverEndpointsToFeeRecipients[endpoint]; + const orders = feeRecipients .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) - .reduce((acc, val) => acc.concat(val), []); + .reduce(flatten, []); return { ...resp, orders, }; }); - // return errors and approvals + // throw informative error + const cancellations = new Array(); throw new CoordinatorServerError( CoordinatorServerErrorMsg.FillFailed, approvedOrders, - [], + cancellations, errorsWithOrders, ); } @@ -755,7 +794,7 @@ export class CoordinatorWrapper extends ContractWrapper { salt: generatePseudoRandomSalt(), signerAddress: normalizedSenderAddress, data, - verifyingContractAddress: this.exchangeAddress, + verifyingContractAddress: this.address, }; const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const signature = await signatureUtils.ecSignHashAsync( @@ -786,7 +825,7 @@ export class CoordinatorWrapper extends ContractWrapper { }, }); - const isError = response.status !== HTTP_OK; + const isError = response.status !== HttpStatus.OK; let json; try { @@ -794,6 +833,7 @@ export class CoordinatorWrapper extends ContractWrapper { } catch (e) { // ignore } + console.log(JSON.stringify(json)); const result = { isError, @@ -854,4 +894,8 @@ function getMakerAddressOrThrow(orders: Array): string { } return orders[0].makerAddress; } +function flatten(acc: T[], val: T | T[]): T[] { + acc.push(...val); + return acc; +} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 608b59c97e..9655cf832c 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -225,61 +225,3 @@ export interface DutchAuctionData { beginTimeSeconds: BigNumber; beginAmount: BigNumber; } - -export interface CoordinatorServerApprovalResponse { - signatures: string[]; - expirationTimeSeconds: BigNumber[]; -} -export interface CoordinatorServerApprovalRawResponse { - signatures: string[]; - expirationTimeSeconds: BigNumber; -} - -export interface CoordinatorServerCancellationResponse { - outstandingFillSignatures: [ - { - orderHash: string; - approvalSignatures: string[]; - expirationTimeSeconds: BigNumber; - takerAssetFillAmount: BigNumber; - } - ]; - cancellationSignatures: string[]; -} - -export interface CoordinatorServerResponse { - isError: boolean; - status: number; - body?: CoordinatorServerCancellationResponse | CoordinatorServerApprovalRawResponse; - error?: any; - request: { - signedTransaction: SignedZeroExTransaction; - txOrigin: string; - }; - coordinatorOperator: string; - orders?: Array; -} - -export class CoordinatorServerError extends Error { - public message: CoordinatorServerErrorMsg; - public approvedOrders?: SignedOrder[] = []; - public cancellations?: CoordinatorServerCancellationResponse[] = []; - public errors: CoordinatorServerResponse[]; - constructor( - message: CoordinatorServerErrorMsg, - approvedOrders: SignedOrder[], - cancellations: CoordinatorServerCancellationResponse[], - errors: CoordinatorServerResponse[], - ) { - super(); - this.message = message; - this.approvedOrders = approvedOrders; - this.cancellations = cancellations; - this.errors = errors; - } -} - -export enum CoordinatorServerErrorMsg { - CancellationFailed = 'Failed to cancel with some coordinator server(s). See errors for more info. See cancellations for successful cancellations.', - FillFailed = 'Failed to obtain approval signatures from some coordinator server(s). See errors for more info. Current transaction has been abandoned but you may resubmit with only approvedOrders (a new ZeroEx transaction will have to be signed).', -} diff --git a/packages/contract-wrappers/src/utils/coordinator_server_types.ts b/packages/contract-wrappers/src/utils/coordinator_server_types.ts new file mode 100644 index 0000000000..9fe360094b --- /dev/null +++ b/packages/contract-wrappers/src/utils/coordinator_server_types.ts @@ -0,0 +1,61 @@ +import { Order, SignedOrder, SignedZeroExTransaction } from '@0x/types'; +import { BigNumber } from '@0x/utils'; + +export interface CoordinatorServerApprovalResponse { + signatures: string[]; + expirationTimeSeconds: BigNumber[]; +} +export interface CoordinatorServerApprovalRawResponse { + signatures: string[]; + expirationTimeSeconds: BigNumber; +} + +export interface CoordinatorServerCancellationResponse { + outstandingFillSignatures: CoordinatorOutstandingFillSignatures[]; + cancellationSignatures: string[]; +} +export interface CoordinatorOutstandingFillSignatures { + orderHash: string; + approvalSignatures: string[]; + expirationTimeSeconds: BigNumber; + takerAssetFillAmount: BigNumber; +} + +export interface CoordinatorServerResponse { + isError: boolean; + status: number; + body?: CoordinatorServerCancellationResponse | CoordinatorServerApprovalRawResponse; + error?: any; + request: CoordinatorServerRequest; + coordinatorOperator: string; + orders?: Array; +} + +export interface CoordinatorServerRequest { + signedTransaction: SignedZeroExTransaction; + txOrigin: string; +} + +export class CoordinatorServerError extends Error { + public message: CoordinatorServerErrorMsg; + public approvedOrders?: SignedOrder[] = []; + public cancellations?: CoordinatorServerCancellationResponse[] = []; + public errors: CoordinatorServerResponse[]; + constructor( + message: CoordinatorServerErrorMsg, + approvedOrders: SignedOrder[], + cancellations: CoordinatorServerCancellationResponse[], + errors: CoordinatorServerResponse[], + ) { + super(); + this.message = message; + this.approvedOrders = approvedOrders; + this.cancellations = cancellations; + this.errors = errors; + } +} + +export enum CoordinatorServerErrorMsg { + CancellationFailed = 'Failed to cancel with some coordinator server(s). See errors for more info. See cancellations for successful cancellations.', + FillFailed = 'Failed to obtain approval signatures from some coordinator server(s). See errors for more info. Current transaction has been abandoned but you may resubmit with only approvedOrders (a new ZeroEx transaction will have to be signed).', +} diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 73ae9400da..1eaf2cf7ce 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -13,7 +13,7 @@ import 'mocha'; import * as nock from 'nock'; import { ContractWrappers } from '../src'; -import { CoordinatorServerErrorMsg } from '../src/types'; +import { CoordinatorServerErrorMsg } from '../src/utils/coordinator_server_types'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; @@ -80,6 +80,7 @@ describe('CoordinatorWrapper', () => { exchangeContractAddress, contractWrappers.erc20Proxy.address, contractWrappers.erc721Proxy.address, + contractAddresses.coordinator, ); [ , diff --git a/packages/fill-scenarios/src/fill_scenarios.ts b/packages/fill-scenarios/src/fill_scenarios.ts index 2bdb8a19a1..7ba5f25b15 100644 --- a/packages/fill-scenarios/src/fill_scenarios.ts +++ b/packages/fill-scenarios/src/fill_scenarios.ts @@ -18,6 +18,7 @@ export class FillScenarios { private readonly _exchangeAddress: string; private readonly _erc20ProxyAddress: string; private readonly _erc721ProxyAddress: string; + private readonly _senderAddress?: string; constructor( supportedProvider: SupportedProvider, userAddresses: string[], @@ -25,6 +26,7 @@ export class FillScenarios { exchangeAddress: string, erc20ProxyAddress: string, erc721ProxyAddress: string, + senderAddress?: string, ) { this._web3Wrapper = new Web3Wrapper(supportedProvider); this._userAddresses = userAddresses; @@ -33,6 +35,7 @@ export class FillScenarios { this._exchangeAddress = exchangeAddress; this._erc20ProxyAddress = erc20ProxyAddress; this._erc721ProxyAddress = erc721ProxyAddress; + this._senderAddress = senderAddress; } public async createFillableSignedOrderAsync( makerAssetData: string, @@ -157,8 +160,7 @@ export class FillScenarios { this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee), this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee), ]); - const senderAddress = constants.NULL_ADDRESS; - + const senderAddress = this._senderAddress; const signedOrder = await orderFactory.createSignedOrderAsync( this._web3Wrapper.getProvider(), makerAddress, diff --git a/yarn.lock b/yarn.lock index 5a56633e38..9def74e6ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -634,18 +634,17 @@ ethereumjs-util "^5.1.1" lodash "^4.17.11" -"@0x/coordinator-server@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-0.1.0.tgz#1b955b03760657c3d9082cc82be641d35a07d064" - integrity sha512-YsCWb/eJ11NZIFxJAdXrRhPIseAxoHUf68rXSHmqcZhth28SX0tkZOcH3dlKNfE7eGTgpbircti7C+CfxXo3/g== +"@0x/coordinator-server@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@0x/coordinator-server/-/coordinator-server-0.1.1.tgz#7eeb74959dc72b76756b95ccd14fd9fa8d072ede" + integrity sha512-KxdZO93TigDyVRC90DMrQDIxjNTq3zMgmW9j8AVzx78nWXiRrUknYnkPP2a1Fp53H6Ngilc33zFjysR+QgrZPA== dependencies: "@0x/assert" "^2.0.8" - "@0x/asset-buyer" "^6.0.5" "@0x/contract-addresses" "^2.3.0" "@0x/contract-wrappers" "^8.0.5" "@0x/contracts-erc20" "^2.1.0" "@0x/json-schemas" "^3.0.8" - "@0x/order-utils" "^7.1.1" + "@0x/order-utils" "^7.2.0" "@0x/subproviders" "^4.0.4" "@0x/types" "^2.2.1" "@0x/typescript-typings" "^4.2.1" @@ -8244,11 +8243,23 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@4.1.15, graceful-fs@^3.0.0, graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~1.2.0: +graceful-fs@^3.0.0: + version "3.0.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + integrity sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg= + dependencies: + natives "^1.1.0" + +graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +graceful-fs@~1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" + integrity sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q= + "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -8763,7 +8774,7 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -http-status-codes@^1.3.0: +http-status-codes@^1.3.0, http-status-codes@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.3.2.tgz#181dfa4455ef454e5e4d827718fca3936680d10d" integrity sha512-nDUtj0ltIt08tGi2VWSpSzNNFye0v3YSe9lX3lIqLTuVvvRiYCvs4QQBSHo0eomFYw1wlUuofurUAlTm+vHnXg== @@ -11709,6 +11720,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natives@^1.1.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.6.tgz#a603b4a498ab77173612b9ea1acdec4d980f00bb" + integrity sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" From 7022fd6d30ccb5329557fe137bf12172c98e367f Mon Sep 17 00:00:00 2001 From: xianny Date: Tue, 7 May 2019 10:38:14 -0700 Subject: [PATCH 16/53] fix exports --- packages/contract-wrappers/src/index.ts | 2 ++ packages/contract-wrappers/src/types.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 66c0b34030..2aee5fb863 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -59,6 +59,8 @@ export { TraderInfo, ValidateOrderFillableOpts, DutchAuctionData, + CoordinatorServerCancellationResponse, + CoordinatorServerError, } from './types'; export { diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 9655cf832c..2db5aae78b 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -225,3 +225,8 @@ export interface DutchAuctionData { beginTimeSeconds: BigNumber; beginAmount: BigNumber; } + +export { + CoordinatorServerCancellationResponse, + CoordinatorServerError, +} from './utils/coordinator_server_types'; From 3325958f1a68bbbd8c2095504a49a6d8e36936e5 Mon Sep 17 00:00:00 2001 From: xianny Date: Tue, 7 May 2019 12:31:31 -0700 Subject: [PATCH 17/53] run only fillorder --- .../contract_wrappers/coordinator_wrapper.ts | 23 ++++++++++++++++++- .../test/coordinator_wrapper_test.ts | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 647b6c26e4..dde8ad9927 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -120,7 +120,28 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrderTx(signedOrder, takerAssetFillAmount); - const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); + const signedTransaction = await this._generateSignedZeroExTransactionAsync(data, takerAddress); + const txOrigin = takerAddress; + const body = { + signedTransaction, + txOrigin, + }; + const endpoint = await this._getServerEndpointOrThrowAsync(signedOrder.feeRecipientAddress); + const response = await fetchAsync(`${endpoint}/v1/request_transaction?networkId=${this.networkId}`, { + body: JSON.stringify(body), + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }); + const json = await response.json(); + console.log(JSON.stringify(json)); + + const {signatures, expirationTimeSeconds} = json; + console.log(signatures); + console.log(expirationTimeSeconds); + const txHash = await this._submitCoordinatorTransactionAsync(signedTransaction, takerAddress, signedTransaction.signature, + [expirationTimeSeconds], signatures, orderTransactionOpts); return txHash; } diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 1eaf2cf7ce..caf79a3af9 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -273,7 +273,7 @@ describe('CoordinatorWrapper', () => { // fill handling is the same for all fill methods so we can test them all through the fillOrder and batchFillOrders interfaces describe('fill order(s)', () => { describe('#fillOrderAsync', () => { - it('should fill a valid order', async () => { + it.only('should fill a valid order', async () => { txHash = await contractWrappers.coordinator.fillOrderAsync( signedOrder, takerTokenFillAmount, From 99e84465decc1d11a29a189d935c281028419f89 Mon Sep 17 00:00:00 2001 From: xianny Date: Tue, 7 May 2019 13:20:55 -0700 Subject: [PATCH 18/53] recover signer address --- .../contract_wrappers/coordinator_wrapper.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index dde8ad9927..bf81e3488c 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -7,6 +7,7 @@ import { Order, SignedOrder, SignedZeroExTransaction, ZeroExTransaction } from ' import { BigNumber, fetchAsync, signTypedDataUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { ContractAbi } from 'ethereum-types'; +import * as ethUtil from 'ethereumjs-util'; import * as HttpStatus from 'http-status-codes'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; @@ -138,10 +139,23 @@ export class CoordinatorWrapper extends ContractWrapper { console.log(JSON.stringify(json)); const {signatures, expirationTimeSeconds} = json; + console.log(`feeRecipient: ${signedOrder.feeRecipientAddress}`); console.log(signatures); console.log(expirationTimeSeconds); - const txHash = await this._submitCoordinatorTransactionAsync(signedTransaction, takerAddress, signedTransaction.signature, - [expirationTimeSeconds], signatures, orderTransactionOpts); + + const typedData = eip712Utils.createCoordinatorApprovalTypedData( + signedTransaction, + this.address, + takerAddress, + expirationTimeSeconds, + ); + const approvalHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); + const recoveredSignerAddress = await this.getSignerAddressAsync(`0x${approvalHashBuff.toString('hex')}`, signatures[0]); + + console.log(`recovered signer: ${recoveredSignerAddress}; feeRecipient: ${signedOrder.feeRecipientAddress}`); + + const txHash = await this._contractInstance.executeTransaction.sendTransactionAsync(signedTransaction, takerAddress, signedTransaction.signature, + [expirationTimeSeconds], signatures, { from: txOrigin }); return txHash; } @@ -807,13 +821,11 @@ export class CoordinatorWrapper extends ContractWrapper { private async _generateSignedZeroExTransactionAsync( data: string, - senderAddress: string, + signerAddress: string, ): Promise { - const normalizedSenderAddress = senderAddress.toLowerCase(); - const transaction: ZeroExTransaction = { salt: generatePseudoRandomSalt(), - signerAddress: normalizedSenderAddress, + signerAddress, data, verifyingContractAddress: this.address, }; From 11c56e6d6def54a9c8d9b9471b646f70812da3ed Mon Sep 17 00:00:00 2001 From: xianny Date: Tue, 7 May 2019 15:21:46 -0700 Subject: [PATCH 19/53] wip --- packages/contract-wrappers/package.json | 2 + .../contract_wrappers/coordinator_wrapper.ts | 20 +++---- .../test/coordinator_wrapper_test.ts | 1 + packages/order-utils/src/index.ts | 2 +- .../order-utils/src/order_validation_utils.ts | 4 +- packages/order-utils/src/signature_utils.ts | 54 +++++++++++++++++-- packages/order-utils/src/types.ts | 2 +- 7 files changed, 67 insertions(+), 18 deletions(-) diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 7b30781da7..96bdbb8cde 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -81,6 +81,8 @@ "@0x/typescript-typings": "^4.2.2", "@0x/utils": "^4.3.1", "@0x/web3-wrapper": "^6.0.5", + "@types/eth-sig-util": "^2.1.0", + "eth-sig-util": "^2.1.2", "ethereum-types": "^2.1.2", "ethereumjs-abi": "0.6.5", "ethereumjs-blockstream": "6.0.0", diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index bf81e3488c..6ceb85f842 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -6,6 +6,7 @@ import { eip712Utils, generatePseudoRandomSalt, signatureUtils, transactionHashU import { Order, SignedOrder, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; import { BigNumber, fetchAsync, signTypedDataUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; +import * as ethSigUtil from 'eth-sig-util'; import { ContractAbi } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as HttpStatus from 'http-status-codes'; @@ -139,7 +140,6 @@ export class CoordinatorWrapper extends ContractWrapper { console.log(JSON.stringify(json)); const {signatures, expirationTimeSeconds} = json; - console.log(`feeRecipient: ${signedOrder.feeRecipientAddress}`); console.log(signatures); console.log(expirationTimeSeconds); @@ -150,10 +150,15 @@ export class CoordinatorWrapper extends ContractWrapper { expirationTimeSeconds, ); const approvalHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); - const recoveredSignerAddress = await this.getSignerAddressAsync(`0x${approvalHashBuff.toString('hex')}`, signatures[0]); + const approvalHashHex = `0x${approvalHashBuff.toString('hex')}`; + const recoveredSignerAddress = await this.getSignerAddressAsync(approvalHashHex, signatures[0]); console.log(`recovered signer: ${recoveredSignerAddress}; feeRecipient: ${signedOrder.feeRecipientAddress}`); + // const rsv = signatureUtils.parseSignatureHexAsRSV(sig.slice(2)); + + // const recoveredTwo = ethUtil.ecrecover(approvalHashBuff, rsv.v, rsv.r, rsv.s); + // console.log(`recovered two: ${recoveredTwo}`); const txHash = await this._contractInstance.executeTransaction.sendTransactionAsync(signedTransaction, takerAddress, signedTransaction.signature, [expirationTimeSeconds], signatures, { from: txOrigin }); return txHash; @@ -829,16 +834,13 @@ export class CoordinatorWrapper extends ContractWrapper { data, verifyingContractAddress: this.address, }; - const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - const signature = await signatureUtils.ecSignHashAsync( + const signedTransaction = await signatureUtils.ecSignTypedDataTransactionAsync( this._web3Wrapper.getProvider(), - transactionHash, + transaction, transaction.signerAddress, ); - return { - ...transaction, - signature, - }; + + return signedTransaction; } private async _executeServerRequestAsync( diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index caf79a3af9..407f647f20 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -274,6 +274,7 @@ describe('CoordinatorWrapper', () => { describe('fill order(s)', () => { describe('#fillOrderAsync', () => { it.only('should fill a valid order', async () => { + console.log(`feeRecipientOne: ${feeRecipientAddressOne}`); txHash = await contractWrappers.coordinator.fillOrderAsync( signedOrder, takerTokenFillAmount, diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 3d90e7043b..05d5d1976c 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -68,7 +68,7 @@ export { } from '@0x/types'; export { - OrderError, + TypedDataError as OrderError, TradeSide, TransferType, FindFeeOrdersThatCoverFeesForTargetOrdersOpts, diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts index 51ab62141d..b0c2c2b219 100644 --- a/packages/order-utils/src/order_validation_utils.ts +++ b/packages/order-utils/src/order_validation_utils.ts @@ -3,7 +3,7 @@ import { BigNumber, providerUtils } from '@0x/utils'; import { SupportedProvider, ZeroExProvider } from 'ethereum-types'; import * as _ from 'lodash'; -import { OrderError, TradeSide, TransferType } from './types'; +import { TradeSide, TransferType, TypedDataError } from './types'; import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher'; import { constants } from './constants'; @@ -211,7 +211,7 @@ export class OrderValidationUtils { signedOrder.makerAddress, ); if (!isValid) { - throw new Error(OrderError.InvalidSignature); + throw new Error(TypedDataError.InvalidSignature); } const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash); if (signedOrder.takerAssetAmount.eq(filledTakerTokenAmount)) { diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 6301236d45..75b58520b4 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -2,7 +2,7 @@ import { ExchangeContract, IValidatorContract, IWalletContract } from '@0x/abi-g import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import * as artifacts from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; -import { ECSignature, Order, SignatureType, SignedOrder, ValidatorSignature } from '@0x/types'; +import { ECSignature, Order, SignatureType, SignedOrder, SignedZeroExTransaction, ValidatorSignature, ZeroExTransaction } from '@0x/types'; import { providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { SupportedProvider } from 'ethereum-types'; @@ -12,7 +12,8 @@ import * as _ from 'lodash'; import { assert } from './assert'; import { eip712Utils } from './eip712_utils'; import { orderHashUtils } from './order_hash'; -import { OrderError } from './types'; +import { transactionHashUtils } from './transaction_hash'; +import { TypedDataError } from './types'; import { utils } from './utils'; export const signatureUtils = { @@ -278,7 +279,50 @@ export const signatureUtils = { } catch (err) { // Detect if Metamask to transition users to the MetamaskSubprovider if ((provider as any).isMetaMask) { - throw new Error(OrderError.InvalidMetamaskSigner); + throw new Error(TypedDataError.InvalidMetamaskSigner); + } else { + throw err; + } + } + }, + /** + * Signs an order using `eth_signTypedData` and returns a SignedOrder. + * @param supportedProvider Web3 provider to use for all JSON RPC requests + * @param transaction The ZeroEx Transaction to sign. + * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address + * must be available via the supplied Provider. + * @return A SignedOrder containing the order and Elliptic curve signature with Signature Type. + */ + async ecSignTypedDataTransactionAsync( + supportedProvider: SupportedProvider, + transaction: ZeroExTransaction, + signerAddress: string, + ): Promise { + const provider = providerUtils.standardizeOrThrow(supportedProvider); + assert.isETHAddressHex('signerAddress', signerAddress); + assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema, [schemas.hexSchema]); + const web3Wrapper = new Web3Wrapper(provider); + await assert.isSenderAddressAsync('signerAddress', signerAddress, web3Wrapper); + const normalizedSignerAddress = signerAddress.toLowerCase(); + const typedData = eip712Utils.createZeroExTransactionTypedData(transaction); + try { + const signature = await web3Wrapper.signTypedDataAsync(normalizedSignerAddress, typedData); + const ecSignatureRSV = parseSignatureHexAsRSV(signature); + const signatureBuffer = Buffer.concat([ + ethUtil.toBuffer(ecSignatureRSV.v), + ethUtil.toBuffer(ecSignatureRSV.r), + ethUtil.toBuffer(ecSignatureRSV.s), + ethUtil.toBuffer(SignatureType.EIP712), + ]); + const signatureHex = `0x${signatureBuffer.toString('hex')}`; + return { + ...transaction, + signature: signatureHex, + }; + } catch (err) { + // Detect if Metamask to transition users to the MetamaskSubprovider + if ((provider as any).isMetaMask) { + throw new Error(TypedDataError.InvalidMetamaskSigner); } else { throw err; } @@ -339,9 +383,9 @@ export const signatureUtils = { } // Detect if Metamask to transition users to the MetamaskSubprovider if ((provider as any).isMetaMask) { - throw new Error(OrderError.InvalidMetamaskSigner); + throw new Error(TypedDataError.InvalidMetamaskSigner); } else { - throw new Error(OrderError.InvalidSignature); + throw new Error(TypedDataError.InvalidSignature); } }, /** diff --git a/packages/order-utils/src/types.ts b/packages/order-utils/src/types.ts index 55ec553dbd..5afd07b112 100644 --- a/packages/order-utils/src/types.ts +++ b/packages/order-utils/src/types.ts @@ -1,6 +1,6 @@ import { BigNumber } from '@0x/utils'; -export enum OrderError { +export enum TypedDataError { InvalidSignature = 'INVALID_SIGNATURE', InvalidMetamaskSigner = "MetaMask provider must be wrapped in a MetamaskSubprovider (from the '@0x/subproviders' package) in order to work with this method.", } From a2b7aa8fa1dae2765ad25a0adce085f5817bb003 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 15:14:12 -0700 Subject: [PATCH 20/53] generate ZeroEx transaction using EIP712 --- .../contract_wrappers/coordinator_wrapper.ts | 82 ++++--------------- packages/contract-wrappers/src/types.ts | 5 +- .../test/coordinator_wrapper_test.ts | 5 +- packages/order-utils/src/signature_utils.ts | 10 ++- yarn.lock | 38 ++++++++- 5 files changed, 66 insertions(+), 74 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 6ceb85f842..2c0bc3c8c7 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -2,18 +2,17 @@ import { CoordinatorContract, CoordinatorRegistryContract, ExchangeContract } fr import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import { Coordinator, CoordinatorRegistry, Exchange } from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; -import { eip712Utils, generatePseudoRandomSalt, signatureUtils, transactionHashUtils } from '@0x/order-utils'; +import { eip712Utils, generatePseudoRandomSalt, signatureUtils } from '@0x/order-utils'; import { Order, SignedOrder, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; import { BigNumber, fetchAsync, signTypedDataUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as ethSigUtil from 'eth-sig-util'; import { ContractAbi } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; import * as HttpStatus from 'http-status-codes'; +import * as _ from 'lodash'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; -import {OrderTransactionOpts} from '../types'; +import { OrderTransactionOpts } from '../types'; import { assert } from '../utils/assert'; import { CoordinatorServerApprovalRawResponse, @@ -27,7 +26,6 @@ import { decorators } from '../utils/decorators'; import { TransactionEncoder } from '../utils/transaction_encoder'; import { ContractWrapper } from './contract_wrapper'; - /** * This class includes all the functionality related to filling or cancelling orders through * the 0x V2 Coordinator extension contract. @@ -66,12 +64,8 @@ export class CoordinatorWrapper extends ContractWrapper { const contractAddresses = getContractAddressesForNetworkOrThrow(networkId); this.address = address === undefined ? contractAddresses.coordinator : address; - this.exchangeAddress = - exchangeAddress === undefined ? contractAddresses.coordinator : exchangeAddress; - this.registryAddress = - registryAddress === undefined - ? contractAddresses.coordinatorRegistry - : registryAddress; + this.exchangeAddress = exchangeAddress === undefined ? contractAddresses.coordinator : exchangeAddress; + this.registryAddress = registryAddress === undefined ? contractAddresses.coordinatorRegistry : registryAddress; this._contractInstance = new CoordinatorContract( this.abi, @@ -122,45 +116,7 @@ export class CoordinatorWrapper extends ContractWrapper { await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); const data = this._transactionEncoder.fillOrderTx(signedOrder, takerAssetFillAmount); - const signedTransaction = await this._generateSignedZeroExTransactionAsync(data, takerAddress); - const txOrigin = takerAddress; - const body = { - signedTransaction, - txOrigin, - }; - const endpoint = await this._getServerEndpointOrThrowAsync(signedOrder.feeRecipientAddress); - const response = await fetchAsync(`${endpoint}/v1/request_transaction?networkId=${this.networkId}`, { - body: JSON.stringify(body), - method: 'POST', - headers: { - 'Content-Type': 'application/json; charset=utf-8', - }, - }); - const json = await response.json(); - console.log(JSON.stringify(json)); - - const {signatures, expirationTimeSeconds} = json; - console.log(signatures); - console.log(expirationTimeSeconds); - - const typedData = eip712Utils.createCoordinatorApprovalTypedData( - signedTransaction, - this.address, - takerAddress, - expirationTimeSeconds, - ); - const approvalHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); - const approvalHashHex = `0x${approvalHashBuff.toString('hex')}`; - const recoveredSignerAddress = await this.getSignerAddressAsync(approvalHashHex, signatures[0]); - - console.log(`recovered signer: ${recoveredSignerAddress}; feeRecipient: ${signedOrder.feeRecipientAddress}`); - - // const rsv = signatureUtils.parseSignatureHexAsRSV(sig.slice(2)); - - // const recoveredTwo = ethUtil.ecrecover(approvalHashBuff, rsv.v, rsv.r, rsv.s); - // console.log(`recovered two: ${recoveredTwo}`); - const txHash = await this._contractInstance.executeTransaction.sendTransactionAsync(signedTransaction, takerAddress, signedTransaction.signature, - [expirationTimeSeconds], signatures, { from: txOrigin }); + const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); return txHash; } @@ -693,7 +649,6 @@ export class CoordinatorWrapper extends ContractWrapper { signedOrders: SignedOrder[], orderTransactionOpts: OrderTransactionOpts, ): Promise { - // const coordinatorOrders = signedOrders.filter(o => o.senderAddress === this.address); // create lookup tables to match server endpoints to orders @@ -732,15 +687,13 @@ export class CoordinatorWrapper extends ContractWrapper { // if no errors if (numErrors === 0) { - // concatenate all approval responses - const allApprovals = approvalResponses - .map(resp => formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse)); - console.log(JSON.stringify(allApprovals)); + const allApprovals = approvalResponses.map(resp => + formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse), + ); + const allSignatures = allApprovals.map(a => a.signatures).reduce(flatten, []); const allExpirationTimes = allApprovals.map(a => a.expirationTimeSeconds).reduce(flatten, []); - console.log(`all signatures: ${JSON.stringify(allSignatures)}`); - console.log(allExpirationTimes); const typedData = eip712Utils.createCoordinatorApprovalTypedData( transaction, @@ -748,10 +701,11 @@ export class CoordinatorWrapper extends ContractWrapper { takerAddress, allExpirationTimes[0], ); - const approvalHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); - const recoveredSignerAddress = await this.getSignerAddressAsync(`0x${approvalHashBuff.toString('hex')}`, allSignatures[0]); - - console.log(`recovered signer: ${recoveredSignerAddress}; feeRecipient: ${JSON.stringify(Object.keys(feeRecipientsToOrders))}`); + const approvalHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); + const recoveredSignerAddress = await this.getSignerAddressAsync( + `0x${approvalHashBuff.toString('hex')}`, + allSignatures[0], + ); // submit transaction with approvals const txHash = await this._submitCoordinatorTransactionAsync( @@ -774,7 +728,8 @@ export class CoordinatorWrapper extends ContractWrapper { .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) .reduce(flatten, []); return orders; - }).reduce(flatten, []); + }) + .reduce(flatten, []); // lookup orders with errors const errorsWithOrders = errorResponses.map(resp => { @@ -832,7 +787,7 @@ export class CoordinatorWrapper extends ContractWrapper { salt: generatePseudoRandomSalt(), signerAddress, data, - verifyingContractAddress: this.address, + verifyingContractAddress: this.exchangeAddress, }; const signedTransaction = await signatureUtils.ecSignTypedDataTransactionAsync( this._web3Wrapper.getProvider(), @@ -868,7 +823,6 @@ export class CoordinatorWrapper extends ContractWrapper { } catch (e) { // ignore } - console.log(JSON.stringify(json)); const result = { isError, diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 2db5aae78b..fba77af231 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -226,7 +226,4 @@ export interface DutchAuctionData { beginAmount: BigNumber; } -export { - CoordinatorServerCancellationResponse, - CoordinatorServerError, -} from './utils/coordinator_server_types'; +export { CoordinatorServerCancellationResponse, CoordinatorServerError } from './utils/coordinator_server_types'; diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 407f647f20..ad769eb241 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -28,7 +28,7 @@ const anotherCoordinatorPort = '4000'; const coordinatorEndpoint = 'http://localhost:'; // tslint:disable:custom-no-magic-numbers -describe('CoordinatorWrapper', () => { +describe.only('CoordinatorWrapper', () => { const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); let coordinatorServerApp: http.Server; @@ -273,8 +273,7 @@ describe('CoordinatorWrapper', () => { // fill handling is the same for all fill methods so we can test them all through the fillOrder and batchFillOrders interfaces describe('fill order(s)', () => { describe('#fillOrderAsync', () => { - it.only('should fill a valid order', async () => { - console.log(`feeRecipientOne: ${feeRecipientAddressOne}`); + it('should fill a valid order', async () => { txHash = await contractWrappers.coordinator.fillOrderAsync( signedOrder, takerTokenFillAmount, diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 75b58520b4..e8f1f88730 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -2,7 +2,15 @@ import { ExchangeContract, IValidatorContract, IWalletContract } from '@0x/abi-g import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import * as artifacts from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; -import { ECSignature, Order, SignatureType, SignedOrder, SignedZeroExTransaction, ValidatorSignature, ZeroExTransaction } from '@0x/types'; +import { + ECSignature, + Order, + SignatureType, + SignedOrder, + SignedZeroExTransaction, + ValidatorSignature, + ZeroExTransaction, +} from '@0x/types'; import { providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { SupportedProvider } from 'ethereum-types'; diff --git a/yarn.lock b/yarn.lock index 9def74e6ae..c4547c628c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1556,6 +1556,13 @@ dependencies: "@types/node" "*" +"@types/eth-sig-util@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/eth-sig-util/-/eth-sig-util-2.1.0.tgz#54497e9c01b5ee3a60475686cce1a20ddccc358b" + integrity sha512-GWX0s/FFGWl6lO2nbd9nq3fh1x47vmLL/p4yDG1+VgCqrip1ErQrbHlTZThtEc6JrcmwCKB2H1de32Hdo3JdJg== + dependencies: + "@types/node" "*" + "@types/ethereum-protocol@*": version "1.0.0" resolved "https://registry.npmjs.org/@types/ethereum-protocol/-/ethereum-protocol-1.0.0.tgz#416e3827d5fdfa4658b0045b35a008747871b271" @@ -4018,7 +4025,7 @@ buffer@^5.0.3, buffer@^5.0.5: base64-js "^1.0.2" ieee754 "^1.1.4" -buffer@^5.1.0: +buffer@^5.1.0, buffer@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" dependencies: @@ -6614,6 +6621,18 @@ eth-sig-util@^1.4.2: ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" ethereumjs-util "^5.1.1" +eth-sig-util@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-2.1.2.tgz#9b357395b5ca07fae6b430d3e534cf0a0f1df118" + integrity sha512-bNgt7txkEmaNlLf+PrbwYIdp4KRkB3E7hW0/QwlBpgv920pVVyQnF0evoovfiRveNKM4OrtPYZTojjmsfuCUOw== + dependencies: + buffer "^5.2.1" + elliptic "^6.4.0" + ethereumjs-abi "0.6.5" + ethereumjs-util "^5.1.1" + tweetnacl "^1.0.0" + tweetnacl-util "^0.15.0" + eth-tx-summary@^3.1.2: version "3.2.1" resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.1.tgz#0c2d5e4c57d2511614f85b9b583c32fa2924166c" @@ -10939,7 +10958,7 @@ lodash.words@^3.0.0: dependencies: lodash._root "^3.0.0" -lodash@4.17.11, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.3: +lodash@4.17.11, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.3: version "4.17.11" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" @@ -10959,6 +10978,11 @@ lodash@^4.17.10: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" +lodash@^4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + lodash@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" @@ -16883,6 +16907,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tweetnacl-util@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.0.tgz#4576c1cee5e2d63d207fee52f1ba02819480bc75" + integrity sha1-RXbBzuXi1j0gf+5S8boCgZSAvHU= + tweetnacl@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.13.2.tgz#453161770469d45cd266c36404e2bc99a8fa9944" @@ -16891,6 +16920,11 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" +tweetnacl@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.1.tgz#2594d42da73cd036bd0d2a54683dd35a6b55ca17" + integrity sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A== + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" From 4fe23f70e2c9098e4bb65838063aeb33617ceb9d Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 16:17:04 -0700 Subject: [PATCH 21/53] wip --- .../contract_wrappers/coordinator_wrapper.ts | 20 +++++-------------- .../test/coordinator_wrapper_test.ts | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 2c0bc3c8c7..6016cdd383 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -649,11 +649,11 @@ export class CoordinatorWrapper extends ContractWrapper { signedOrders: SignedOrder[], orderTransactionOpts: OrderTransactionOpts, ): Promise { - // const coordinatorOrders = signedOrders.filter(o => o.senderAddress === this.address); + const coordinatorOrders = signedOrders.filter(o => o.senderAddress === this.address); // create lookup tables to match server endpoints to orders const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; - for (const order of signedOrders) { + for (const order of coordinatorOrders) { const feeRecipient = order.feeRecipientAddress; if (feeRecipientsToOrders[feeRecipient] === undefined) { feeRecipientsToOrders[feeRecipient] = [] as SignedOrder[]; @@ -695,18 +695,6 @@ export class CoordinatorWrapper extends ContractWrapper { const allSignatures = allApprovals.map(a => a.signatures).reduce(flatten, []); const allExpirationTimes = allApprovals.map(a => a.expirationTimeSeconds).reduce(flatten, []); - const typedData = eip712Utils.createCoordinatorApprovalTypedData( - transaction, - this.address, - takerAddress, - allExpirationTimes[0], - ); - const approvalHashBuff = signTypedDataUtils.generateTypedDataHash(typedData); - const recoveredSignerAddress = await this.getSignerAddressAsync( - `0x${approvalHashBuff.toString('hex')}`, - allSignatures[0], - ); - // submit transaction with approvals const txHash = await this._submitCoordinatorTransactionAsync( transaction, @@ -720,6 +708,7 @@ export class CoordinatorWrapper extends ContractWrapper { } else { // format errors and approvals // concatenate approvals + const notCoordinatorOrders = signedOrders.filter(o => o.senderAddress !== this.address); const approvedOrders = approvalResponses .map(resp => { const endpoint = resp.coordinatorOperator; @@ -729,7 +718,8 @@ export class CoordinatorWrapper extends ContractWrapper { .reduce(flatten, []); return orders; }) - .reduce(flatten, []); + .reduce(flatten, []) + .concat(notCoordinatorOrders); // lookup orders with errors const errorsWithOrders = errorResponses.map(resp => { diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index ad769eb241..075221dae0 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -273,7 +273,7 @@ describe.only('CoordinatorWrapper', () => { // fill handling is the same for all fill methods so we can test them all through the fillOrder and batchFillOrders interfaces describe('fill order(s)', () => { describe('#fillOrderAsync', () => { - it('should fill a valid order', async () => { + it.only('should fill a valid order', async () => { txHash = await contractWrappers.coordinator.fillOrderAsync( signedOrder, takerTokenFillAmount, From edc0511767bf75e6d2ecde091b90bcc05f7da014 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 16:42:54 -0700 Subject: [PATCH 22/53] update Coordinator artifact --- .../artifacts/Coordinator.json | 256 +++++++++++++++--- .../test/coordinator_wrapper_test.ts | 4 +- 2 files changed, 218 insertions(+), 42 deletions(-) diff --git a/packages/contract-artifacts/artifacts/Coordinator.json b/packages/contract-artifacts/artifacts/Coordinator.json index 3c56715a8d..c8af051309 100644 --- a/packages/contract-artifacts/artifacts/Coordinator.json +++ b/packages/contract-artifacts/artifacts/Coordinator.json @@ -27,7 +27,7 @@ "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { "components": [ @@ -46,32 +46,58 @@ ], "name": "transaction", "type": "tuple" - }, - { - "name": "txOrigin", - "type": "address" - }, + } + ], + "name": "getTransactionHash", + "outputs": [ { - "name": "transactionSignature", - "type": "bytes" - }, + "name": "transactionHash", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ { - "name": "approvalExpirationTimeSeconds", - "type": "uint256[]" - }, + "components": [ + { + "name": "txOrigin", + "type": "address" + }, + { + "name": "transactionHash", + "type": "bytes32" + }, + { + "name": "transactionSignature", + "type": "bytes" + }, + { + "name": "approvalExpirationTimeSeconds", + "type": "uint256" + } + ], + "name": "approval", + "type": "tuple" + } + ], + "name": "getCoordinatorApprovalHash", + "outputs": [ { - "name": "approvalSignatures", - "type": "bytes[]" + "name": "approvalHash", + "type": "bytes32" } ], - "name": "executeTransaction", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "components": [ @@ -108,16 +134,16 @@ "type": "bytes[]" } ], - "name": "assertValidCoordinatorApprovals", + "name": "executeTransaction", "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], - "name": "EIP712_DOMAIN_HASH", + "name": "EIP712_EXCHANGE_DOMAIN_HASH", "outputs": [ { "name": "", @@ -149,6 +175,39 @@ "name": "transaction", "type": "tuple" }, + { + "name": "txOrigin", + "type": "address" + }, + { + "name": "transactionSignature", + "type": "bytes" + }, + { + "name": "approvalExpirationTimeSeconds", + "type": "uint256[]" + }, + { + "name": "approvalSignatures", + "type": "bytes[]" + } + ], + "name": "assertValidCoordinatorApprovals", + "outputs": [], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "data", + "type": "bytes" + } + ], + "name": "decodeOrdersFromFillData", + "outputs": [ { "components": [ { @@ -202,26 +261,22 @@ ], "name": "orders", "type": "tuple[]" - }, - { - "name": "txOrigin", - "type": "address" - }, - { - "name": "transactionSignature", - "type": "bytes" - }, - { - "name": "approvalExpirationTimeSeconds", - "type": "uint256[]" - }, + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EIP712_COORDINATOR_DOMAIN_HASH", + "outputs": [ { - "name": "approvalSignatures", - "type": "bytes[]" + "name": "", + "type": "bytes32" } ], - "name": "assertValidTransactionOrdersApproval", - "outputs": [], "payable": false, "stateMutability": "view", "type": "function" @@ -241,9 +296,130 @@ "evm": { "bytecode": { "linkReferences": {}, - "object": "0x60806040523480156200001157600080fd5b506040516020806200238083398101806040526200003391908101906200022b565b604080517f454950373132446f6d61696e28000000000000000000000000000000000000006020808301919091527f737472696e67206e616d652c0000000000000000000000000000000000000000602d8301527f737472696e672076657273696f6e2c000000000000000000000000000000000060398301527f6164647265737320766572696679696e67436f6e74726163740000000000000060488301527f29000000000000000000000000000000000000000000000000000000000000006061830152825180830360420181526062830180855281519183019190912060a28401855260179091527f30782050726f746f636f6c20436f6f7264696e61746f7200000000000000000060829093019290925282518084018452600581527f312e302e30000000000000000000000000000000000000000000000000000000908201528251808201929092527f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236828401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c6060830152306080808401919091528351808403909101815260a0909201909252805191012060005560018054600160a060020a031916600160a060020a039290921691909117905562000273565b600062000224825162000260565b9392505050565b6000602082840312156200023e57600080fd5b60006200024c848462000216565b949350505050565b600160a060020a031690565b60006200026d8262000254565b92915050565b6120fd80620002836000396000f3fe608060405234801561001057600080fd5b5060043610610084576000357c010000000000000000000000000000000000000000000000000000000090048063d2df07331161006d578063d2df0733146100c7578063e306f779146100da578063e3b1aa86146100ef57610084565b80630f7d8e391461008957806390c3bc3f146100b2575b600080fd5b61009c610097366004611888565b610102565b6040516100a99190611e6f565b60405180910390f35b6100c56100c036600461196e565b6104f7565b005b6100c56100d536600461196e565b6105a3565b6100e26105d4565b6040516100a99190611e7d565b6100c56100fd366004611a42565b6105da565b6000808251111515610149576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f3b565b60405180910390fd5b600061015483610821565b7f010000000000000000000000000000000000000000000000000000000000000090049050600360ff8216106101b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611efb565b60008160ff1660038111156101c757fe5b905060008160038111156101d757fe5b141561020f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f2b565b600181600381111561021d57fe5b141561035b57835160411461025e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611e8b565b600084600081518110151561026f57fe5b01602001517f010000000000000000000000000000000000000000000000000000000000000090819004810204905060006102b186600163ffffffff6108e516565b905060006102c687602163ffffffff6108e516565b905060018884848460405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610325573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104f195505050505050565b600281600381111561036957fe5b14156104bf5783516041146103aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611e8b565b60008460008151811015156103bb57fe5b01602001517f010000000000000000000000000000000000000000000000000000000000000090819004810204905060006103fd86600163ffffffff6108e516565b9050600061041287602163ffffffff6108e516565b905060018860405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012084848460405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610325573d6000803e3d6000fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611efb565b92915050565b61050485858585856105a3565b6001548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056a93909290918990600401611f5b565b600060405180830381600087803b15801561058457600080fd5b505af1158015610598573d6000803e3d6000fd5b505050505050505050565b60606105b28660400151610930565b90506000815111156105cc576105cc8682878787876105da565b505050505050565b60005481565b3273ffffffffffffffffffffffffffffffffffffffff851614610629576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f0b565b600061063487610de8565b60408051600080825260208201909252845192935091905b80821461073c576000868281518110151561066357fe5b906020019060200201519050610677611220565b506040805160808101825273ffffffffffffffffffffffffffffffffffffffff8b16815260208101879052908101899052606081018290524282116106e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611edb565b60006106f382610dfb565b90506000610718828a8781518110151561070957fe5b90602001906020020151610102565b905061072a878263ffffffff610e0916565b9650506001909301925061064c915050565b5061074d823263ffffffff610e0916565b885190925060005b8082146108145789516000908b908390811061076d57fe5b906020019060200201516060015173ffffffffffffffffffffffffffffffffffffffff16141561079c5761080c565b60008a828151811015156107ac57fe5b6020908102909101015160400151905060006107ce868363ffffffff610ed316565b9050801515610809576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611e9b565b50505b600101610755565b5050505050505050505050565b600080825111151561085f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f1b565b815182907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811061088f57fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01909252507f0100000000000000000000000000000000000000000000000000000000000000908190040290565b600081602001835110151515610927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611eeb565b50016020015190565b60606000610944838263ffffffff610f1016565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d50000000000000000000000000000000000000000000000000000000014806109d757507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b80610a2357507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610aad57610a30611248565b8351610a4690859060049063ffffffff610f7d16565b806020019051610a5991908101906118da565b604080516001808252818301909252919250816020015b610a78611248565b815260200190600190039081610a7057905050925080836000815181101515610a9d57fe5b6020908102909101015250610de2565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b000000000000000000000000000000000000000000000000000000001480610b3e57507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b80610b8a57507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b80610bd657507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b80610c2257507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b80610c6e57507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b80610cba57507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b15610cef578251610cd590849060049063ffffffff610f7d16565b806020019051610ce8919081019061184b565b9150610de2565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610de257610d41611248565b610d49611248565b8451610d5f90869060049063ffffffff610f7d16565b806020019051610d72919081019061190f565b60408051600280825260608201909252929450909250816020015b610d95611248565b815260200190600190039081610d8d57905050935081846000815181101515610dba57fe5b602090810290910101528351819085906001908110610dd557fe5b6020908102909101015250505b50919050565b60006104f1610df683611049565b6110b7565b60006104f1610df6836110f7565b815160405160609184906020808202808401820192910182851015610e5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611ecb565b82851115610e7457610e6d858583611156565b8497508793505b600182019150602081019050808401925082945081885284604052868860018403815181101515610ea157fe5b73ffffffffffffffffffffffffffffffffffffffff909216602092830290910190910152508694505050505092915050565b6000602083510260208401818101815b81811015610f0657805180871415610efd57600195508291505b50602001610ee3565b5050505092915050565b600081600401835110151515610f52576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f4b565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610fb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611eab565b8351821115610ff4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611ebb565b8282036040519080825280601f01601f191660200182016040528015611021576020820181803883390190505b5090506110426110308261121a565b8461103a8761121a565b018351611156565b9392505050565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b6000546040517f19010000000000000000000000000000000000000000000000000000000000008152600281019190915260228101919091526042902090565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b6020811015611180576001816020036101000a038019835116818551168082178652505050611215565b8282141561118d57611215565b828211156111c75760208103905080820181840181515b828510156111bf5784518652602095860195909401936111a4565b905250611215565b60208103905080820181840183515b8186121561121057825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe092830192909101906111d6565b855250505b505050565b60200190565b6040805160808101825260008082526020820181905260609282018390529181019190915290565b61018060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b60006110428235612038565b60006110428251612038565b6000601f8201831361132b57600080fd5b813561133e61133982611fcd565b611fa6565b81815260209384019390925082018360005b83811015610f06578135860161136688826114b2565b8452506020928301929190910190600101611350565b6000601f8201831361138d57600080fd5b815161139b61133982611fcd565b81815260209384019390925082018360005b83811015610f0657815186016113c38882611690565b84525060209283019291909101906001016113ad565b6000601f820183136113ea57600080fd5b81356113f861133982611fcd565b81815260209384019390925082018360005b83811015610f0657813586016114208882611547565b845250602092830192919091019060010161140a565b6000601f8201831361144757600080fd5b813561145561133982611fcd565b9150818183526020840193506020810190508385602084028201111561147a57600080fd5b60005b83811015610f06578161149088826114a6565b845250602092830192919091019060010161147d565b60006110428235612043565b6000601f820183136114c357600080fd5b81356114d161133982611fee565b915080825260208301602083018583830111156114ed57600080fd5b6114f883828461205f565b50505092915050565b6000601f8201831361151257600080fd5b815161152061133982611fee565b9150808252602083016020830185838301111561153c57600080fd5b6114f883828461206b565b6000610180828403121561155a57600080fd5b611565610180611fa6565b905060006115738484611302565b825250602061158484848301611302565b602083015250604061159884828501611302565b60408301525060606115ac84828501611302565b60608301525060806115c0848285016114a6565b60808301525060a06115d4848285016114a6565b60a08301525060c06115e8848285016114a6565b60c08301525060e06115fc848285016114a6565b60e083015250610100611611848285016114a6565b61010083015250610120611627848285016114a6565b6101208301525061014082013567ffffffffffffffff81111561164957600080fd5b611655848285016114b2565b6101408301525061016082013567ffffffffffffffff81111561167757600080fd5b611683848285016114b2565b6101608301525092915050565b600061018082840312156116a357600080fd5b6116ae610180611fa6565b905060006116bc848461130e565b82525060206116cd8484830161130e565b60208301525060406116e18482850161130e565b60408301525060606116f58482850161130e565b60608301525060806117098482850161183f565b60808301525060a061171d8482850161183f565b60a08301525060c06117318482850161183f565b60c08301525060e06117458482850161183f565b60e08301525061010061175a8482850161183f565b610100830152506101206117708482850161183f565b6101208301525061014082015167ffffffffffffffff81111561179257600080fd5b61179e84828501611501565b6101408301525061016082015167ffffffffffffffff8111156117c057600080fd5b61168384828501611501565b6000606082840312156117de57600080fd5b6117e86060611fa6565b905060006117f684846114a6565b825250602061180784848301611302565b602083015250604082013567ffffffffffffffff81111561182757600080fd5b611833848285016114b2565b60408301525092915050565b60006110428251612043565b60006020828403121561185d57600080fd5b815167ffffffffffffffff81111561187457600080fd5b6118808482850161137c565b949350505050565b6000806040838503121561189b57600080fd5b60006118a785856114a6565b925050602083013567ffffffffffffffff8111156118c457600080fd5b6118d0858286016114b2565b9150509250929050565b6000602082840312156118ec57600080fd5b815167ffffffffffffffff81111561190357600080fd5b61188084828501611690565b6000806040838503121561192257600080fd5b825167ffffffffffffffff81111561193957600080fd5b61194585828601611690565b925050602083015167ffffffffffffffff81111561196257600080fd5b6118d085828601611690565b600080600080600060a0868803121561198657600080fd5b853567ffffffffffffffff81111561199d57600080fd5b6119a9888289016117cc565b95505060206119ba88828901611302565b945050604086013567ffffffffffffffff8111156119d757600080fd5b6119e3888289016114b2565b935050606086013567ffffffffffffffff811115611a0057600080fd5b611a0c88828901611436565b925050608086013567ffffffffffffffff811115611a2957600080fd5b611a358882890161131a565b9150509295509295909350565b60008060008060008060c08789031215611a5b57600080fd5b863567ffffffffffffffff811115611a7257600080fd5b611a7e89828a016117cc565b965050602087013567ffffffffffffffff811115611a9b57600080fd5b611aa789828a016113d9565b9550506040611ab889828a01611302565b945050606087013567ffffffffffffffff811115611ad557600080fd5b611ae189828a016114b2565b935050608087013567ffffffffffffffff811115611afe57600080fd5b611b0a89828a01611436565b92505060a087013567ffffffffffffffff811115611b2757600080fd5b611b3389828a0161131a565b9150509295509295509295565b611b4981612038565b82525050565b611b4981612043565b6000611b6382612034565b808452611b7781602086016020860161206b565b611b808161209b565b9093016020019392505050565b601281527f4c454e4754485f36355f52455155495245440000000000000000000000000000602082015260400190565b601a81527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000602082015260400190565b601a81527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000602082015260400190565b601c81527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000602082015260400190565b601781527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000602082015260400190565b601081527f415050524f56414c5f4558504952454400000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601581527f5349474e41545552455f554e535550504f525445440000000000000000000000602082015260400190565b600e81527f494e56414c49445f4f524947494e000000000000000000000000000000000000602082015260400190565b602181527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560208201527f4400000000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f5349474e41545552455f494c4c4547414c000000000000000000000000000000602082015260400190565b601e81527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000602082015260400190565b602581527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160208201527f5549524544000000000000000000000000000000000000000000000000000000604082015260600190565b602081016104f18284611b40565b602081016104f18284611b4f565b602080825281016104f181611b8d565b602080825281016104f181611bbd565b602080825281016104f181611bed565b602080825281016104f181611c1d565b602080825281016104f181611c4d565b602080825281016104f181611c7d565b602080825281016104f181611cad565b602080825281016104f181611d03565b602080825281016104f181611d33565b602080825281016104f181611d63565b602080825281016104f181611db9565b602080825281016104f181611de9565b602080825281016104f181611e19565b60808101611f698287611b4f565b611f766020830186611b40565b8181036040830152611f888185611b58565b90508181036060830152611f9c8184611b58565b9695505050505050565b60405181810167ffffffffffffffff81118282101715611fc557600080fd5b604052919050565b600067ffffffffffffffff821115611fe457600080fd5b5060209081020190565b600067ffffffffffffffff82111561200557600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b5190565b60006104f182612046565b90565b73ffffffffffffffffffffffffffffffffffffffff1690565b82818337506000910152565b60005b8381101561208657818101518382015260200161206e565b83811115612095576000848401525b50505050565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169056fea265627a7a7230582013be4e9e281ff59b6be3d1c4c7af6075c7d255edc60be429d25841f98f287b3e6c6578706572696d656e74616cf50037" + "object": "0x60806040523480156200001157600080fd5b506040516020806200235b833981018060405262000033919081019062000252565b600080546001600160a01b0319166001600160a01b0383161790556040516200005f906020016200029f565b60408051601f1981840301815282825280516020918201208383018352601784527f30782050726f746f636f6c20436f6f7264696e61746f720000000000000000009382019390935281518083018352600581527f312e302e300000000000000000000000000000000000000000000000000000009082015290516200012d92917f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236917f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9130910162000284565b60408051601f198184030181529082905280516020918201206001556200015591016200029f565b60408051601f1981840301815282825280516020918201208383018352600b84527f30782050726f746f636f6c0000000000000000000000000000000000000000009382019390935281518083018352600181527f32000000000000000000000000000000000000000000000000000000000000009082015260005491516200023093927ff0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61e927fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5926001600160a01b03909216910162000284565b60408051601f1981840301815291905280516020909101206002555062000360565b6000602082840312156200026557600080fd5b81516001600160a01b03811681146200027d57600080fd5b9392505050565b93845260208401929092526040830152606082015260800190565b7f454950373132446f6d61696e280000000000000000000000000000000000000081527f737472696e67206e616d652c0000000000000000000000000000000000000000600d8201527f737472696e672076657273696f6e2c000000000000000000000000000000000060198201527f6164647265737320766572696679696e67436f6e74726163740000000000000060288201527f2900000000000000000000000000000000000000000000000000000000000000604182015260420190565b611feb80620003706000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH3 0x11 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH3 0x235B DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE PUSH3 0x33 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH3 0x252 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND OR SWAP1 SSTORE PUSH1 0x40 MLOAD PUSH3 0x5F SWAP1 PUSH1 0x20 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0x17 DUP5 MSTORE PUSH32 0x30782050726F746F636F6C20436F6F7264696E61746F72000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x5 DUP2 MSTORE PUSH32 0x312E302E30000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE SWAP1 MLOAD PUSH3 0x12D SWAP3 SWAP2 PUSH32 0x626D101E477FD17DD52AFB3F9AD9EB016BF60F6E377877F34E8F3EA84C930236 SWAP2 PUSH32 0x6C015BD22B4C69690933C1058878EBDFEF31F9AAAE40BBE86D8A09FE1B2972C SWAP2 ADDRESS SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 PUSH1 0x1 SSTORE PUSH3 0x155 SWAP2 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0xB DUP5 MSTORE PUSH32 0x30782050726F746F636F6C000000000000000000000000000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x1 DUP2 MSTORE PUSH32 0x3200000000000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE PUSH1 0x0 SLOAD SWAP2 MLOAD PUSH3 0x230 SWAP4 SWAP3 PUSH32 0xF0F24618F4C4BE1E62E026FB039A20EF96F4495294817D1027FFAA6D1F70E61E SWAP3 PUSH32 0xAD7C5BEF027816A800DA1736444FB58A807EF4C9603B7848673F7E3A68EB14A5 SWAP3 PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP2 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP1 SWAP2 ADD KECCAK256 PUSH1 0x2 SSTORE POP PUSH3 0x360 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH3 0x265 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH3 0x27D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0x20 DUP5 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH32 0x454950373132446F6D61696E2800000000000000000000000000000000000000 DUP2 MSTORE PUSH32 0x737472696E67206E616D652C0000000000000000000000000000000000000000 PUSH1 0xD DUP3 ADD MSTORE PUSH32 0x737472696E672076657273696F6E2C0000000000000000000000000000000000 PUSH1 0x19 DUP3 ADD MSTORE PUSH32 0x6164647265737320766572696679696E67436F6E747261637400000000000000 PUSH1 0x28 DUP3 ADD MSTORE PUSH32 0x2900000000000000000000000000000000000000000000000000000000000000 PUSH1 0x41 DUP3 ADD MSTORE PUSH1 0x42 ADD SWAP1 JUMP JUMPDEST PUSH2 0x1FEB DUP1 PUSH3 0x370 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC26CFECD GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xC26CFECD EQ PUSH2 0xFE JUMPI DUP1 PUSH4 0xD2DF0733 EQ PUSH2 0x106 JUMPI DUP1 PUSH4 0xEE55B968 EQ PUSH2 0x119 JUMPI DUP1 PUSH4 0xFB6961CC EQ PUSH2 0x139 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0xF7D8E39 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x23872F55 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0x48A321D6 EQ PUSH2 0xD6 JUMPI DUP1 PUSH4 0x90C3BC3F EQ PUSH2 0xE9 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA0 PUSH2 0x9B CALLDATASIZE PUSH1 0x4 PUSH2 0x15D7 JUMP JUMPDEST PUSH2 0x141 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1958 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xC9 PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x177C JUMP JUMPDEST PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1AAD JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xE4 CALLDATASIZE PUSH1 0x4 PUSH2 0x165B JUMP JUMPDEST PUSH2 0x4E7 JUMP JUMPDEST PUSH2 0xFC PUSH2 0xF7 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x4FA JUMP JUMPDEST STOP JUMPDEST PUSH2 0xC9 PUSH2 0x5A6 JUMP JUMPDEST PUSH2 0xFC PUSH2 0x114 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x5AC JUMP JUMPDEST PUSH2 0x12C PUSH2 0x127 CALLDATASIZE PUSH1 0x4 PUSH2 0x161E JUMP JUMPDEST PUSH2 0x5DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1979 JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xA8F JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0x186 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D7D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x191 DUP4 PUSH2 0xA95 JUMP JUMPDEST PUSH1 0xF8 SHR SWAP1 POP PUSH1 0x4 DUP2 LT PUSH2 0x1D0 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0xFF AND PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1E1 JUMPI INVALID JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1F1 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x229 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D46 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x237 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x2A8 JUMPI DUP4 MLOAD ISZERO PUSH2 0x276 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1E48 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DB4 JUMP JUMPDEST PUSH1 0x2 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x2B6 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x3BB JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x2F7 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x306 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x329 DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x33E DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x385 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP7 POP PUSH2 0x4CE SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x3 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x3C9 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x49C JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x40A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x419 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x43C DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x451 DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x466 SWAP2 SWAP1 PUSH2 0x1927 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4E2 DUP4 PUSH2 0xB61 JUMP JUMPDEST PUSH2 0xBCF JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4F5 DUP4 PUSH2 0xBDD JUMP JUMPDEST PUSH2 0xC3C JUMP JUMPDEST PUSH2 0x507 DUP6 DUP6 DUP6 DUP6 DUP6 PUSH2 0x5AC JUMP JUMPDEST PUSH1 0x0 SLOAD DUP6 MLOAD PUSH1 0x20 DUP8 ADD MLOAD PUSH1 0x40 DUP1 DUP10 ADD MLOAD SWAP1 MLOAD PUSH32 0xBFC8BFCE00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP5 AND SWAP4 PUSH4 0xBFC8BFCE SWAP4 PUSH2 0x56D SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP10 SWAP1 PUSH1 0x4 ADD PUSH2 0x1E7F JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x587 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x59B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x60 PUSH2 0x5BB DUP7 PUSH1 0x40 ADD MLOAD PUSH2 0x5DB JUMP JUMPDEST DUP1 MLOAD SWAP1 SWAP2 POP ISZERO PUSH2 0x5D3 JUMPI PUSH2 0x5D3 DUP7 DUP3 DUP8 DUP8 DUP8 DUP8 PUSH2 0xC4A JUMP JUMPDEST POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x0 PUSH2 0x5EF DUP4 DUP3 PUSH4 0xFFFFFFFF PUSH2 0xE98 AND JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xB4BE83D500000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x682 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3E228BAE00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x6CE JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x64A3BC1500000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x757 JUMPI PUSH2 0x6DB PUSH2 0x11DB JUMP JUMPDEST DUP4 MLOAD PUSH2 0x6F1 SWAP1 DUP6 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x704 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x16ED JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 DUP1 DUP3 MSTORE DUP2 DUP4 ADD SWAP1 SWAP3 MSTORE SWAP2 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0x723 PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x71B JUMPI SWAP1 POP POP SWAP3 POP DUP1 DUP4 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x746 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x297BB70B00000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x7E8 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x50DDE19000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x834 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x4D0AE54600000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x880 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xE5FA431B00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x8CC JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xA3E2038000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x918 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x7E1D980800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x964 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xDD1C7D1800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x999 JUMPI DUP3 MLOAD PUSH2 0x97F SWAP1 DUP5 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x992 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x154B JUMP JUMPDEST SWAP2 POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 EQ ISZERO PUSH2 0xA89 JUMPI PUSH2 0x9EB PUSH2 0x11DB JUMP JUMPDEST PUSH2 0x9F3 PUSH2 0x11DB JUMP JUMPDEST DUP5 MLOAD PUSH2 0xA09 SWAP1 DUP7 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0xA1C SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x1722 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 ADD SWAP1 SWAP3 MSTORE SWAP3 SWAP5 POP SWAP1 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0xA3F PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0xA37 JUMPI SWAP1 POP POP SWAP4 POP DUP2 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0xA62 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP DUP1 DUP5 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0xA7B JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP POP JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x1 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0xAD1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CE9 JUMP JUMPDEST DUP2 PUSH1 0x1 DUP4 MLOAD SUB DUP2 MLOAD DUP2 LT PUSH2 0xAE1 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD DUP3 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ADD SWAP1 SWAP3 MSTORE POP PUSH1 0xF8 SWAP1 DUP2 SHR SWAP1 SHL SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO PUSH2 0xB58 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C1E JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP2 DUP2 ADD MLOAD DUP3 MLOAD PUSH1 0x20 SWAP4 DUP5 ADD MLOAD DUP3 MLOAD SWAP3 DUP6 ADD SWAP3 SWAP1 SWAP3 KECCAK256 DUP4 MLOAD PUSH32 0x213C6F636F3EA94E701C0ADF9B2624AA45A6C694F9A292C094F9A81C24B5DF4C DUP2 MSTORE SWAP5 DUP6 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x2 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST PUSH1 0x40 DUP1 DUP3 ADD MLOAD DUP3 MLOAD PUSH1 0x20 DUP1 DUP6 ADD MLOAD PUSH1 0x60 DUP7 DUP2 ADD MLOAD DUP6 MLOAD SWAP6 DUP5 ADD SWAP6 SWAP1 SWAP6 KECCAK256 DUP7 MLOAD PUSH32 0x2FBCDBAA76BC7589916958AE919DFBEF04D23F6BBF26DE6FF317B32C6CC01E05 DUP2 MSTORE SWAP4 DUP5 ADD SWAP5 SWAP1 SWAP5 MSTORE SWAP5 DUP3 ADD MSTORE SWAP3 DUP4 ADD MSTORE PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 SWAP1 KECCAK256 SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x1 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST ORIGIN PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND EQ PUSH2 0xC99 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CB2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xCA4 DUP8 PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 SWAP3 MSTORE DUP5 MLOAD SWAP3 SWAP4 POP SWAP2 SWAP1 JUMPDEST DUP2 DUP2 EQ PUSH2 0xDA5 JUMPI PUSH1 0x0 DUP7 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xCD1 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD SWAP1 POP PUSH2 0xCE3 PUSH2 0x1294 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP11 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 MSTORE POP SWAP1 POP TIMESTAMP DUP3 GT PUSH2 0xD55 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BE7 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xD60 DUP3 PUSH2 0x4E7 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xD81 DUP3 DUP11 DUP8 DUP2 MLOAD DUP2 LT PUSH2 0xD74 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH2 0x141 JUMP JUMPDEST SWAP1 POP PUSH2 0xD93 DUP8 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST SWAP7 POP POP PUSH1 0x1 SWAP1 SWAP4 ADD SWAP3 POP PUSH2 0xCBC SWAP2 POP POP JUMP JUMPDEST POP PUSH2 0xDB6 DUP3 ORIGIN PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST DUP9 MLOAD SWAP1 SWAP3 POP PUSH1 0x0 JUMPDEST DUP2 DUP2 EQ PUSH2 0xE8B JUMPI PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xDE9 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x60 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xE16 JUMPI PUSH2 0xE83 JUMP JUMPDEST PUSH1 0x0 DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xE24 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x40 ADD MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0xE47 DUP3 DUP8 PUSH2 0x10D0 SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST SWAP1 POP DUP1 PUSH2 0xE80 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B0B JUMP JUMPDEST POP POP JUMPDEST PUSH1 0x1 ADD PUSH2 0xDBE JUMP JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x4 ADD DUP4 MLOAD LT ISZERO PUSH2 0xED8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DEB JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 AND SWAP1 JUMP JUMPDEST PUSH1 0x60 DUP2 DUP4 GT ISZERO PUSH2 0xF3F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B42 JUMP JUMPDEST DUP4 MLOAD DUP3 GT ISZERO PUSH2 0xF7A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B79 JUMP JUMPDEST DUP3 DUP3 SUB PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0xFA7 JUMPI PUSH1 0x20 DUP3 ADD DUP2 DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH2 0xFC8 PUSH2 0xFB6 DUP3 PUSH2 0x1111 JUMP JUMPDEST DUP5 PUSH2 0xFC0 DUP8 PUSH2 0x1111 JUMP JUMPDEST ADD DUP4 MLOAD PUSH2 0x1117 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x2 DUP2 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x22 DUP3 ADD MSTORE PUSH1 0x42 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST DUP2 MLOAD PUSH1 0x40 MLOAD PUSH1 0x60 SWAP2 DUP5 SWAP1 PUSH1 0x20 DUP1 DUP3 MUL DUP1 DUP5 ADD DUP3 ADD SWAP3 SWAP2 ADD DUP3 DUP6 LT ISZERO PUSH2 0x105A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BB0 JUMP JUMPDEST DUP3 DUP6 GT ISZERO PUSH2 0x1074 JUMPI PUSH2 0x106D DUP6 DUP6 DUP4 PUSH2 0x1117 JUMP JUMPDEST DUP5 SWAP8 POP DUP8 SWAP4 POP JUMPDEST PUSH1 0x1 DUP3 ADD SWAP2 POP PUSH1 0x20 DUP2 ADD SWAP1 POP DUP1 DUP5 ADD SWAP3 POP DUP3 SWAP5 POP DUP2 DUP9 MSTORE DUP5 PUSH1 0x40 MSTORE DUP7 DUP9 PUSH1 0x1 DUP5 SUB DUP2 MLOAD DUP2 LT PUSH2 0x109F JUMPI INVALID JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND PUSH1 0x20 SWAP3 DUP4 MUL SWAP2 SWAP1 SWAP2 ADD SWAP1 SWAP2 ADD MSTORE POP SWAP6 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP4 MLOAD MUL PUSH1 0x20 DUP5 ADD DUP2 DUP2 ADD DUP2 SWAP3 POP JUMPDEST DUP1 DUP4 LT ISZERO PUSH2 0x1108 JUMPI DUP3 MLOAD DUP1 DUP7 EQ ISZERO PUSH2 0x10FC JUMPI PUSH1 0x1 SWAP5 POP DUP2 SWAP4 POP JUMPDEST POP PUSH1 0x20 DUP4 ADD SWAP3 POP PUSH2 0x10E2 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1141 JUMPI PUSH1 0x1 DUP2 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP4 MLOAD AND DUP2 DUP6 MLOAD AND DUP1 DUP3 OR DUP7 MSTORE POP POP POP PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 EQ ISZERO PUSH2 0x114E JUMPI PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 GT ISZERO PUSH2 0x1188 JUMPI PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP2 MLOAD JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x1180 JUMPI DUP5 MLOAD DUP7 MSTORE PUSH1 0x20 SWAP6 DUP7 ADD SWAP6 SWAP1 SWAP5 ADD SWAP4 PUSH2 0x1165 JUMP JUMPDEST SWAP1 MSTORE POP PUSH2 0x11D6 JUMP JUMPDEST PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP4 MLOAD JUMPDEST DUP2 DUP7 SLT ISZERO PUSH2 0x11D1 JUMPI DUP3 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP3 DUP4 ADD SWAP3 SWAP1 SWAP2 ADD SWAP1 PUSH2 0x1197 JUMP JUMPDEST DUP6 MSTORE POP POP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH2 0x180 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP1 NOT AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x4CE DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x12F0 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1303 PUSH2 0x12FE DUP3 PUSH2 0x1EF8 JUMP JUMPDEST PUSH2 0x1ED1 JUMP JUMPDEST DUP2 DUP2 MSTORE SWAP2 POP PUSH1 0x20 DUP1 DUP4 ADD SWAP1 DUP5 ADD PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1340 JUMPI PUSH2 0x132B DUP8 PUSH1 0x20 DUP5 CALLDATALOAD DUP10 ADD ADD PUSH2 0x134A JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 SWAP3 DUP4 ADD SWAP3 SWAP2 SWAP1 SWAP2 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1313 JUMP JUMPDEST POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x135A JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1368 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x137F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x13A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH2 0x13B7 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x13CE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x13DF DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x13F9 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x1402 DUP2 PUSH2 0x1ED1 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x140F DUP4 DUP4 PUSH2 0x12D5 JUMP JUMPDEST DUP2 MSTORE PUSH2 0x141E DUP4 PUSH1 0x20 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH2 0x1430 DUP4 PUSH1 0x40 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD MSTORE PUSH2 0x1442 DUP4 PUSH1 0x60 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP3 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP3 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP3 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x14A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x14B0 DUP7 DUP4 DUP8 ADD PUSH2 0x1398 JUMP JUMPDEST DUP4 DUP6 ADD MSTORE PUSH2 0x160 SWAP3 POP DUP3 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x14CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x14D9 DUP6 DUP3 DUP7 ADD PUSH2 0x1398 JUMP JUMPDEST DUP3 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x14F6 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x1500 PUSH1 0x60 PUSH2 0x1ED1 JUMP JUMPDEST SWAP1 POP DUP2 CALLDATALOAD DUP2 MSTORE PUSH1 0x20 DUP3 ADD CALLDATALOAD PUSH2 0x1514 DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1533 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x153F DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x155D JUMPI DUP2 DUP3 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1573 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP1 DUP5 ADD DUP6 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1584 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 MLOAD SWAP2 POP PUSH2 0x1594 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP4 DUP2 ADD SWAP1 DUP3 DUP6 ADD DUP7 JUMPDEST DUP6 DUP2 LT ISZERO PUSH2 0x15C9 JUMPI PUSH2 0x15B7 DUP11 DUP9 DUP5 MLOAD DUP9 ADD ADD PUSH2 0x13E6 JUMP JUMPDEST DUP5 MSTORE SWAP3 DUP7 ADD SWAP3 SWAP1 DUP7 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x15A0 JUMP JUMPDEST POP SWAP1 SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x15EA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 CALLDATALOAD SWAP2 POP PUSH1 0x20 DUP4 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1608 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x134A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x1630 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1647 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x166C JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x1683 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x80 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x1695 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x169F PUSH1 0x80 PUSH2 0x1ED1 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD PUSH2 0x16AC DUP2 PUSH2 0x1F8C JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 DUP2 DUP2 ADD CALLDATALOAD SWAP1 DUP5 ADD MSTORE PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x16C9 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x16D5 DUP8 DUP3 DUP5 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP PUSH1 0x60 SWAP1 DUP2 ADD CALLDATALOAD SWAP1 DUP4 ADD MSTORE POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x16FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1716 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x1735 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x174D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1759 DUP7 DUP4 DUP8 ADD PUSH2 0x13E6 JUMP JUMPDEST SWAP4 POP PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x176F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x178E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x17A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x14E5 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x17C8 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x17DF JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x17EB DUP10 DUP4 DUP11 ADD PUSH2 0x14E5 JUMP JUMPDEST SWAP7 POP PUSH1 0x20 SWAP2 POP DUP2 DUP9 ADD CALLDATALOAD PUSH2 0x17FE DUP2 PUSH2 0x1F8C JUMP JUMPDEST SWAP6 POP PUSH1 0x40 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1811 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x181D DUP11 DUP3 DUP12 ADD PUSH2 0x134A JUMP JUMPDEST SWAP6 POP POP PUSH1 0x60 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1831 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 DUP10 ADD DUP11 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1842 JUMPI DUP5 DUP6 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP2 POP PUSH2 0x1852 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP5 DUP2 ADD SWAP1 DUP3 DUP7 ADD DUP7 DUP6 MUL DUP5 ADD DUP8 ADD DUP15 LT ISZERO PUSH2 0x186E JUMPI DUP8 DUP9 REVERT JUMPDEST DUP8 SWAP4 POP JUMPDEST DUP5 DUP5 LT ISZERO PUSH2 0x1890 JUMPI DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x1 SWAP4 SWAP1 SWAP4 ADD SWAP3 SWAP2 DUP7 ADD SWAP2 DUP7 ADD PUSH2 0x1872 JUMP JUMPDEST POP SWAP7 POP POP POP POP PUSH1 0x80 DUP9 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x18A9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x18B6 DUP9 DUP3 DUP10 ADD PUSH2 0x12E0 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 POP SWAP3 SWAP6 SWAP1 SWAP4 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 MSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x18F5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE PUSH1 0x1C DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x3C ADD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x1AA0 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE DUP2 MLOAD PUSH2 0x180 PUSH2 0x19DE DUP8 DUP4 MLOAD PUSH2 0x18C3 JUMP JUMPDEST DUP8 DUP3 ADD MLOAD PUSH2 0x19EE DUP10 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0x1A01 PUSH1 0x40 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0x1A14 PUSH1 0x60 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP9 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP9 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP9 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP9 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD DUP3 DUP3 DUP11 ADD MSTORE PUSH2 0x1A6D DUP4 DUP11 ADD DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 SWAP2 POP DUP2 DUP4 ADD MLOAD DUP9 DUP3 SUB DUP4 DUP11 ADD MSTORE PUSH2 0x1A8A DUP3 DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP9 POP POP POP SWAP5 DUP8 ADD SWAP5 POP POP SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x199F JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x12 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F36355F52455155495245440000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F415050524F56414C5F5349474E4154555245000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x46524F4D5F4C4553535F5448414E5F544F5F5245515549524544000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1C SWAP1 DUP3 ADD MSTORE PUSH32 0x544F5F4C4553535F5448414E5F4C454E4754485F524551554952454400000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x17 SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F465245455F4D454D4F52595F505452000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x10 SWAP1 DUP3 ADD MSTORE PUSH32 0x415050524F56414C5F4558504952454400000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x26 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x15 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F554E535550504F525445440000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F4F524947494E000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x21 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F5448414E5F5A45524F5F4C454E4754485F52455155495245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x4400000000000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494C4C4547414C000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1E SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F475245415445525F5448414E5F305F52455155495245440000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494E56414C4944000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x25 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F345F4C454E4754485F524551 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5549524544000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F305F5245515549524544000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP6 DUP3 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH1 0x80 PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1EB4 PUSH1 0x80 DUP4 ADD DUP6 PUSH2 0x18DD JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x60 DUP5 ADD MSTORE PUSH2 0x1EC6 DUP2 DUP6 PUSH2 0x18DD JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1EF0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F0F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 SWAP1 DUP2 MUL ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F30 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1F77 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1F5F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1F86 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x1FAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xbc 0xdb 0x4a 0xab RETURNDATACOPY BYTE DIV 0xea 0x5c 0xd6 0xc1 CODESIZE SWAP2 GT AND 0xce 0xac EXTCODEHASH 0xac DUP9 0xde NOT SWAP6 0xc4 0xd3 CALLCODE 0x4f 0xdd EXTCODEHASH TIMESTAMP 0xf 0xb6 PUSH13 0x6578706572696D656E74616CF5 STOP CALLDATACOPY ", + "sourceMap": "838:227:0:-;;;978:85;8:9:-1;5:2;;;30:1;27;20:12;5:2;978:85:0;;;;;;;;;;;;;;;;;;;;;;830:8:8;:35;;-1:-1:-1;;;;;;830:35:8;-1:-1:-1;;;;;830:35:8;;;;;1425:148:10;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2101:30;;;;;;;;;;;;;;;;2163:33;;;;;;;;;;;;;;;2006:238;;;;1415:159;2085:48;;2147:51;;2228:4;;2006:238;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2006:238:10;;;;1996:249;;49:4:-1;1996:249:10;;;;1963:30;:282;1425:148;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2391:27;;;;;;;;;;;;;;;;2450:30;;;;;;;;;;;;;;;-1:-1:-1;2512:8:10;2296:236;;;;1415:159;2375:45;;2434:48;;-1:-1:-1;;;;;2512:8:10;;;;2296:236;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2296:236:10;;;2286:247;;49:4:-1;2286:247:10;;;;2256:27;:277;-1:-1:-1;838:227:0;;146:263:-1;;261:2;249:9;240:7;236:23;232:32;229:2;;;-1:-1;;267:12;229:2;89:6;83:13;-1:-1;;;;;5679:5;5285:54;5654:5;5651:35;5641:2;;-1:-1;;5690:12;5641:2;319:74;223:186;-1:-1;;;223:186;2777:661;505:58;;;3077:2;3068:12;;505:58;;;;3179:12;;;505:58;3290:12;;;505:58;3401:12;;;2968:470;3445:1440;2506:66;2486:87;;872:66;2470:2;2592:12;;852:87;2097:66;958:12;;;2077:87;1281:66;2183:12;;;1261:87;1689:66;1367:12;;;1669:87;1775:11;;;4029:856;;838:227:0;;;;;;" + }, + "deployedBytecode": { + "linkReferences": {}, + "object": "0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC26CFECD GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xC26CFECD EQ PUSH2 0xFE JUMPI DUP1 PUSH4 0xD2DF0733 EQ PUSH2 0x106 JUMPI DUP1 PUSH4 0xEE55B968 EQ PUSH2 0x119 JUMPI DUP1 PUSH4 0xFB6961CC EQ PUSH2 0x139 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0xF7D8E39 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x23872F55 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0x48A321D6 EQ PUSH2 0xD6 JUMPI DUP1 PUSH4 0x90C3BC3F EQ PUSH2 0xE9 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA0 PUSH2 0x9B CALLDATASIZE PUSH1 0x4 PUSH2 0x15D7 JUMP JUMPDEST PUSH2 0x141 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1958 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xC9 PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x177C JUMP JUMPDEST PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1AAD JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xE4 CALLDATASIZE PUSH1 0x4 PUSH2 0x165B JUMP JUMPDEST PUSH2 0x4E7 JUMP JUMPDEST PUSH2 0xFC PUSH2 0xF7 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x4FA JUMP JUMPDEST STOP JUMPDEST PUSH2 0xC9 PUSH2 0x5A6 JUMP JUMPDEST PUSH2 0xFC PUSH2 0x114 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x5AC JUMP JUMPDEST PUSH2 0x12C PUSH2 0x127 CALLDATASIZE PUSH1 0x4 PUSH2 0x161E JUMP JUMPDEST PUSH2 0x5DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1979 JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xA8F JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0x186 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D7D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x191 DUP4 PUSH2 0xA95 JUMP JUMPDEST PUSH1 0xF8 SHR SWAP1 POP PUSH1 0x4 DUP2 LT PUSH2 0x1D0 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0xFF AND PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1E1 JUMPI INVALID JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1F1 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x229 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D46 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x237 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x2A8 JUMPI DUP4 MLOAD ISZERO PUSH2 0x276 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1E48 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DB4 JUMP JUMPDEST PUSH1 0x2 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x2B6 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x3BB JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x2F7 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x306 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x329 DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x33E DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x385 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP7 POP PUSH2 0x4CE SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x3 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x3C9 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x49C JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x40A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x419 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x43C DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x451 DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x466 SWAP2 SWAP1 PUSH2 0x1927 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4E2 DUP4 PUSH2 0xB61 JUMP JUMPDEST PUSH2 0xBCF JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4F5 DUP4 PUSH2 0xBDD JUMP JUMPDEST PUSH2 0xC3C JUMP JUMPDEST PUSH2 0x507 DUP6 DUP6 DUP6 DUP6 DUP6 PUSH2 0x5AC JUMP JUMPDEST PUSH1 0x0 SLOAD DUP6 MLOAD PUSH1 0x20 DUP8 ADD MLOAD PUSH1 0x40 DUP1 DUP10 ADD MLOAD SWAP1 MLOAD PUSH32 0xBFC8BFCE00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP5 AND SWAP4 PUSH4 0xBFC8BFCE SWAP4 PUSH2 0x56D SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP10 SWAP1 PUSH1 0x4 ADD PUSH2 0x1E7F JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x587 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x59B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x60 PUSH2 0x5BB DUP7 PUSH1 0x40 ADD MLOAD PUSH2 0x5DB JUMP JUMPDEST DUP1 MLOAD SWAP1 SWAP2 POP ISZERO PUSH2 0x5D3 JUMPI PUSH2 0x5D3 DUP7 DUP3 DUP8 DUP8 DUP8 DUP8 PUSH2 0xC4A JUMP JUMPDEST POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x0 PUSH2 0x5EF DUP4 DUP3 PUSH4 0xFFFFFFFF PUSH2 0xE98 AND JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xB4BE83D500000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x682 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3E228BAE00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x6CE JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x64A3BC1500000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x757 JUMPI PUSH2 0x6DB PUSH2 0x11DB JUMP JUMPDEST DUP4 MLOAD PUSH2 0x6F1 SWAP1 DUP6 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x704 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x16ED JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 DUP1 DUP3 MSTORE DUP2 DUP4 ADD SWAP1 SWAP3 MSTORE SWAP2 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0x723 PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x71B JUMPI SWAP1 POP POP SWAP3 POP DUP1 DUP4 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x746 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x297BB70B00000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x7E8 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x50DDE19000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x834 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x4D0AE54600000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x880 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xE5FA431B00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x8CC JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xA3E2038000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x918 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x7E1D980800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x964 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xDD1C7D1800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x999 JUMPI DUP3 MLOAD PUSH2 0x97F SWAP1 DUP5 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x992 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x154B JUMP JUMPDEST SWAP2 POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 EQ ISZERO PUSH2 0xA89 JUMPI PUSH2 0x9EB PUSH2 0x11DB JUMP JUMPDEST PUSH2 0x9F3 PUSH2 0x11DB JUMP JUMPDEST DUP5 MLOAD PUSH2 0xA09 SWAP1 DUP7 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0xA1C SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x1722 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 ADD SWAP1 SWAP3 MSTORE SWAP3 SWAP5 POP SWAP1 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0xA3F PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0xA37 JUMPI SWAP1 POP POP SWAP4 POP DUP2 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0xA62 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP DUP1 DUP5 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0xA7B JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP POP JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x1 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0xAD1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CE9 JUMP JUMPDEST DUP2 PUSH1 0x1 DUP4 MLOAD SUB DUP2 MLOAD DUP2 LT PUSH2 0xAE1 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD DUP3 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ADD SWAP1 SWAP3 MSTORE POP PUSH1 0xF8 SWAP1 DUP2 SHR SWAP1 SHL SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO PUSH2 0xB58 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C1E JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP2 DUP2 ADD MLOAD DUP3 MLOAD PUSH1 0x20 SWAP4 DUP5 ADD MLOAD DUP3 MLOAD SWAP3 DUP6 ADD SWAP3 SWAP1 SWAP3 KECCAK256 DUP4 MLOAD PUSH32 0x213C6F636F3EA94E701C0ADF9B2624AA45A6C694F9A292C094F9A81C24B5DF4C DUP2 MSTORE SWAP5 DUP6 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x2 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST PUSH1 0x40 DUP1 DUP3 ADD MLOAD DUP3 MLOAD PUSH1 0x20 DUP1 DUP6 ADD MLOAD PUSH1 0x60 DUP7 DUP2 ADD MLOAD DUP6 MLOAD SWAP6 DUP5 ADD SWAP6 SWAP1 SWAP6 KECCAK256 DUP7 MLOAD PUSH32 0x2FBCDBAA76BC7589916958AE919DFBEF04D23F6BBF26DE6FF317B32C6CC01E05 DUP2 MSTORE SWAP4 DUP5 ADD SWAP5 SWAP1 SWAP5 MSTORE SWAP5 DUP3 ADD MSTORE SWAP3 DUP4 ADD MSTORE PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 SWAP1 KECCAK256 SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x1 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST ORIGIN PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND EQ PUSH2 0xC99 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CB2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xCA4 DUP8 PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 SWAP3 MSTORE DUP5 MLOAD SWAP3 SWAP4 POP SWAP2 SWAP1 JUMPDEST DUP2 DUP2 EQ PUSH2 0xDA5 JUMPI PUSH1 0x0 DUP7 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xCD1 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD SWAP1 POP PUSH2 0xCE3 PUSH2 0x1294 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP11 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 MSTORE POP SWAP1 POP TIMESTAMP DUP3 GT PUSH2 0xD55 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BE7 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xD60 DUP3 PUSH2 0x4E7 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xD81 DUP3 DUP11 DUP8 DUP2 MLOAD DUP2 LT PUSH2 0xD74 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH2 0x141 JUMP JUMPDEST SWAP1 POP PUSH2 0xD93 DUP8 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST SWAP7 POP POP PUSH1 0x1 SWAP1 SWAP4 ADD SWAP3 POP PUSH2 0xCBC SWAP2 POP POP JUMP JUMPDEST POP PUSH2 0xDB6 DUP3 ORIGIN PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST DUP9 MLOAD SWAP1 SWAP3 POP PUSH1 0x0 JUMPDEST DUP2 DUP2 EQ PUSH2 0xE8B JUMPI PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xDE9 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x60 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xE16 JUMPI PUSH2 0xE83 JUMP JUMPDEST PUSH1 0x0 DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xE24 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x40 ADD MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0xE47 DUP3 DUP8 PUSH2 0x10D0 SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST SWAP1 POP DUP1 PUSH2 0xE80 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B0B JUMP JUMPDEST POP POP JUMPDEST PUSH1 0x1 ADD PUSH2 0xDBE JUMP JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x4 ADD DUP4 MLOAD LT ISZERO PUSH2 0xED8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DEB JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 AND SWAP1 JUMP JUMPDEST PUSH1 0x60 DUP2 DUP4 GT ISZERO PUSH2 0xF3F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B42 JUMP JUMPDEST DUP4 MLOAD DUP3 GT ISZERO PUSH2 0xF7A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B79 JUMP JUMPDEST DUP3 DUP3 SUB PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0xFA7 JUMPI PUSH1 0x20 DUP3 ADD DUP2 DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH2 0xFC8 PUSH2 0xFB6 DUP3 PUSH2 0x1111 JUMP JUMPDEST DUP5 PUSH2 0xFC0 DUP8 PUSH2 0x1111 JUMP JUMPDEST ADD DUP4 MLOAD PUSH2 0x1117 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x2 DUP2 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x22 DUP3 ADD MSTORE PUSH1 0x42 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST DUP2 MLOAD PUSH1 0x40 MLOAD PUSH1 0x60 SWAP2 DUP5 SWAP1 PUSH1 0x20 DUP1 DUP3 MUL DUP1 DUP5 ADD DUP3 ADD SWAP3 SWAP2 ADD DUP3 DUP6 LT ISZERO PUSH2 0x105A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BB0 JUMP JUMPDEST DUP3 DUP6 GT ISZERO PUSH2 0x1074 JUMPI PUSH2 0x106D DUP6 DUP6 DUP4 PUSH2 0x1117 JUMP JUMPDEST DUP5 SWAP8 POP DUP8 SWAP4 POP JUMPDEST PUSH1 0x1 DUP3 ADD SWAP2 POP PUSH1 0x20 DUP2 ADD SWAP1 POP DUP1 DUP5 ADD SWAP3 POP DUP3 SWAP5 POP DUP2 DUP9 MSTORE DUP5 PUSH1 0x40 MSTORE DUP7 DUP9 PUSH1 0x1 DUP5 SUB DUP2 MLOAD DUP2 LT PUSH2 0x109F JUMPI INVALID JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND PUSH1 0x20 SWAP3 DUP4 MUL SWAP2 SWAP1 SWAP2 ADD SWAP1 SWAP2 ADD MSTORE POP SWAP6 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP4 MLOAD MUL PUSH1 0x20 DUP5 ADD DUP2 DUP2 ADD DUP2 SWAP3 POP JUMPDEST DUP1 DUP4 LT ISZERO PUSH2 0x1108 JUMPI DUP3 MLOAD DUP1 DUP7 EQ ISZERO PUSH2 0x10FC JUMPI PUSH1 0x1 SWAP5 POP DUP2 SWAP4 POP JUMPDEST POP PUSH1 0x20 DUP4 ADD SWAP3 POP PUSH2 0x10E2 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1141 JUMPI PUSH1 0x1 DUP2 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP4 MLOAD AND DUP2 DUP6 MLOAD AND DUP1 DUP3 OR DUP7 MSTORE POP POP POP PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 EQ ISZERO PUSH2 0x114E JUMPI PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 GT ISZERO PUSH2 0x1188 JUMPI PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP2 MLOAD JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x1180 JUMPI DUP5 MLOAD DUP7 MSTORE PUSH1 0x20 SWAP6 DUP7 ADD SWAP6 SWAP1 SWAP5 ADD SWAP4 PUSH2 0x1165 JUMP JUMPDEST SWAP1 MSTORE POP PUSH2 0x11D6 JUMP JUMPDEST PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP4 MLOAD JUMPDEST DUP2 DUP7 SLT ISZERO PUSH2 0x11D1 JUMPI DUP3 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP3 DUP4 ADD SWAP3 SWAP1 SWAP2 ADD SWAP1 PUSH2 0x1197 JUMP JUMPDEST DUP6 MSTORE POP POP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH2 0x180 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP1 NOT AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x4CE DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x12F0 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1303 PUSH2 0x12FE DUP3 PUSH2 0x1EF8 JUMP JUMPDEST PUSH2 0x1ED1 JUMP JUMPDEST DUP2 DUP2 MSTORE SWAP2 POP PUSH1 0x20 DUP1 DUP4 ADD SWAP1 DUP5 ADD PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1340 JUMPI PUSH2 0x132B DUP8 PUSH1 0x20 DUP5 CALLDATALOAD DUP10 ADD ADD PUSH2 0x134A JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 SWAP3 DUP4 ADD SWAP3 SWAP2 SWAP1 SWAP2 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1313 JUMP JUMPDEST POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x135A JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1368 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x137F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x13A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH2 0x13B7 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x13CE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x13DF DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x13F9 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x1402 DUP2 PUSH2 0x1ED1 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x140F DUP4 DUP4 PUSH2 0x12D5 JUMP JUMPDEST DUP2 MSTORE PUSH2 0x141E DUP4 PUSH1 0x20 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH2 0x1430 DUP4 PUSH1 0x40 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD MSTORE PUSH2 0x1442 DUP4 PUSH1 0x60 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP3 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP3 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP3 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x14A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x14B0 DUP7 DUP4 DUP8 ADD PUSH2 0x1398 JUMP JUMPDEST DUP4 DUP6 ADD MSTORE PUSH2 0x160 SWAP3 POP DUP3 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x14CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x14D9 DUP6 DUP3 DUP7 ADD PUSH2 0x1398 JUMP JUMPDEST DUP3 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x14F6 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x1500 PUSH1 0x60 PUSH2 0x1ED1 JUMP JUMPDEST SWAP1 POP DUP2 CALLDATALOAD DUP2 MSTORE PUSH1 0x20 DUP3 ADD CALLDATALOAD PUSH2 0x1514 DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1533 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x153F DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x155D JUMPI DUP2 DUP3 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1573 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP1 DUP5 ADD DUP6 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1584 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 MLOAD SWAP2 POP PUSH2 0x1594 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP4 DUP2 ADD SWAP1 DUP3 DUP6 ADD DUP7 JUMPDEST DUP6 DUP2 LT ISZERO PUSH2 0x15C9 JUMPI PUSH2 0x15B7 DUP11 DUP9 DUP5 MLOAD DUP9 ADD ADD PUSH2 0x13E6 JUMP JUMPDEST DUP5 MSTORE SWAP3 DUP7 ADD SWAP3 SWAP1 DUP7 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x15A0 JUMP JUMPDEST POP SWAP1 SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x15EA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 CALLDATALOAD SWAP2 POP PUSH1 0x20 DUP4 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1608 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x134A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x1630 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1647 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x166C JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x1683 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x80 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x1695 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x169F PUSH1 0x80 PUSH2 0x1ED1 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD PUSH2 0x16AC DUP2 PUSH2 0x1F8C JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 DUP2 DUP2 ADD CALLDATALOAD SWAP1 DUP5 ADD MSTORE PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x16C9 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x16D5 DUP8 DUP3 DUP5 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP PUSH1 0x60 SWAP1 DUP2 ADD CALLDATALOAD SWAP1 DUP4 ADD MSTORE POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x16FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1716 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x1735 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x174D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1759 DUP7 DUP4 DUP8 ADD PUSH2 0x13E6 JUMP JUMPDEST SWAP4 POP PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x176F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x178E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x17A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x14E5 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x17C8 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x17DF JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x17EB DUP10 DUP4 DUP11 ADD PUSH2 0x14E5 JUMP JUMPDEST SWAP7 POP PUSH1 0x20 SWAP2 POP DUP2 DUP9 ADD CALLDATALOAD PUSH2 0x17FE DUP2 PUSH2 0x1F8C JUMP JUMPDEST SWAP6 POP PUSH1 0x40 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1811 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x181D DUP11 DUP3 DUP12 ADD PUSH2 0x134A JUMP JUMPDEST SWAP6 POP POP PUSH1 0x60 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1831 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 DUP10 ADD DUP11 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1842 JUMPI DUP5 DUP6 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP2 POP PUSH2 0x1852 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP5 DUP2 ADD SWAP1 DUP3 DUP7 ADD DUP7 DUP6 MUL DUP5 ADD DUP8 ADD DUP15 LT ISZERO PUSH2 0x186E JUMPI DUP8 DUP9 REVERT JUMPDEST DUP8 SWAP4 POP JUMPDEST DUP5 DUP5 LT ISZERO PUSH2 0x1890 JUMPI DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x1 SWAP4 SWAP1 SWAP4 ADD SWAP3 SWAP2 DUP7 ADD SWAP2 DUP7 ADD PUSH2 0x1872 JUMP JUMPDEST POP SWAP7 POP POP POP POP PUSH1 0x80 DUP9 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x18A9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x18B6 DUP9 DUP3 DUP10 ADD PUSH2 0x12E0 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 POP SWAP3 SWAP6 SWAP1 SWAP4 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 MSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x18F5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE PUSH1 0x1C DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x3C ADD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x1AA0 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE DUP2 MLOAD PUSH2 0x180 PUSH2 0x19DE DUP8 DUP4 MLOAD PUSH2 0x18C3 JUMP JUMPDEST DUP8 DUP3 ADD MLOAD PUSH2 0x19EE DUP10 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0x1A01 PUSH1 0x40 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0x1A14 PUSH1 0x60 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP9 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP9 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP9 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP9 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD DUP3 DUP3 DUP11 ADD MSTORE PUSH2 0x1A6D DUP4 DUP11 ADD DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 SWAP2 POP DUP2 DUP4 ADD MLOAD DUP9 DUP3 SUB DUP4 DUP11 ADD MSTORE PUSH2 0x1A8A DUP3 DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP9 POP POP POP SWAP5 DUP8 ADD SWAP5 POP POP SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x199F JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x12 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F36355F52455155495245440000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F415050524F56414C5F5349474E4154555245000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x46524F4D5F4C4553535F5448414E5F544F5F5245515549524544000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1C SWAP1 DUP3 ADD MSTORE PUSH32 0x544F5F4C4553535F5448414E5F4C454E4754485F524551554952454400000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x17 SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F465245455F4D454D4F52595F505452000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x10 SWAP1 DUP3 ADD MSTORE PUSH32 0x415050524F56414C5F4558504952454400000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x26 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x15 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F554E535550504F525445440000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F4F524947494E000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x21 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F5448414E5F5A45524F5F4C454E4754485F52455155495245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x4400000000000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494C4C4547414C000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1E SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F475245415445525F5448414E5F305F52455155495245440000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494E56414C4944000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x25 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F345F4C454E4754485F524551 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5549524544000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F305F5245515549524544000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP6 DUP3 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH1 0x80 PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1EB4 PUSH1 0x80 DUP4 ADD DUP6 PUSH2 0x18DD JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x60 DUP5 ADD MSTORE PUSH2 0x1EC6 DUP2 DUP6 PUSH2 0x18DD JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1EF0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F0F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 SWAP1 DUP2 MUL ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F30 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1F77 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1F5F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1F86 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x1FAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xbc 0xdb 0x4a 0xab RETURNDATACOPY BYTE DIV 0xea 0x5c 0xd6 0xc1 CODESIZE SWAP2 GT AND 0xce 0xac EXTCODEHASH 0xac DUP9 0xde NOT SWAP6 0xc4 0xd3 CALLCODE 0x4f 0xdd EXTCODEHASH TIMESTAMP 0xf 0xb6 PUSH13 0x6578706572696D656E74616CF5 STOP CALLDATACOPY ", + "sourceMap": "838:227:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;838:227:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;988:3006:3;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;1646:352:11;;;;;;;;;:::i;:::-;;;;;;;;1996:268:9;;;;;;;;;:::i;1627:801:2:-;;;;;;;;;:::i;:::-;;1870:42:10;;;:::i;2108:917:1:-;;;;;;;;;:::i;3237:1762::-;;;;;;;;;:::i;:::-;;;;;;;;1701:45:10;;;:::i;988:3006:3:-;1097:21;1174:1;1155:9;:16;:20;1134:97;;;;;;;;;;;;;;;;;;;;;;1296:22;1327:23;:9;:21;:23::i;:::-;1321:30;;;-1:-1:-1;1449:29:3;1424:55;;1403:123;;;;;;;;;;;;;;1537:27;1581:16;1567:31;;;;;;;;;;1537:61;-1:-1:-1;1948:21:3;1931:13;:38;;;;;;;;;1927:1717;;;1985:27;;;;;;;;;;;1927:1717;2294:21;2277:13;:38;;;;;;;;;2273:1371;;;2356:16;;:21;2331:97;;;;;;;;;;;;;;2442:27;;;;;;;;;;;2273:1371;2542:20;2525:13;:37;;;;;;;;;2521:1123;;;2603:9;:16;2623:2;2603:22;2578:99;;;;;;;;;;;;;;2691:7;2707:9;2717:1;2707:12;;;;;;;;;;;;;;;;;;2701:19;;;-1:-1:-1;2734:9:3;2746:24;:9;2768:1;2746:24;:21;:24;:::i;:::-;2734:36;-1:-1:-1;2784:9:3;2796:25;:9;2818:2;2796:25;:21;:25;:::i;:::-;2784:37;;2851:102;2878:4;2900:1;2919;2938;2851:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;2851:102:3;;;;;;-1:-1:-1;2967:20:3;;-1:-1:-1;;;;;;2967:20:3;2521:1123;3064:21;3047:13;:38;;;;;;;;;3043:601;;;3126:9;:16;3146:2;3126:22;3101:99;;;;;;;;;;;;;;3214:7;3230:9;3240:1;3230:12;;;;;;;;;;;;;;;;;;3224:19;;;-1:-1:-1;3257:9:3;3269:24;:9;3291:1;3269:24;:21;:24;:::i;:::-;3257:36;-1:-1:-1;3307:9:3;3319:25;:9;3341:2;3319:25;:21;:25;:::i;:::-;3307:37;;3374:225;3505:4;3411:116;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;3411:116:3;;;3401:127;;;;;;3546:1;3565;3584;3374:225;;;;;;;;;;;;;;;;;;;3043:601;3956:31;;;;;;;;;;;988:3006;;;;;:::o;1646:352:11:-;1757:23;1898:61;1924:34;1946:11;1924:21;:34::i;:::-;1898:25;:61::i;1996:268:9:-;2114:20;2165:63;2194:33;2218:8;2194:23;:33::i;:::-;2165:28;:63::i;1627:801:2:-;2008:197;2053:11;2078:8;2100:20;2134:29;2177:18;2008:31;:197::i;:::-;2251:8;;2292:16;;2322:25;;;;2361:16;;;;;2251:170;;;;;:8;;;;;:27;;:170;;2292:16;;2322:25;;2391:20;;2251:170;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2251:170:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2251:170:2;;;;1627:801;;;;;:::o;1870:42:10:-;;;;:::o;2108:917:1:-;2511:30;2544:42;2569:11;:16;;;2544:24;:42::i;:::-;2657:13;;2511:75;;-1:-1:-1;2657:17:1;2653:366;;2758:250;2812:11;2841:6;2865:8;2891:20;2929:29;2976:18;2758:36;:250::i;:::-;2108:917;;;;;;:::o;3237:1762::-;3335:30;3381:15;3399:18;:4;3381:15;3399:18;:15;:18;:::i;:::-;3381:36;-1:-1:-1;3444:31:1;;;3456:19;3444:31;;:87;;-1:-1:-1;3491:40:1;;;3503:28;3491:40;3444:87;:142;;;-1:-1:-1;3547:39:1;;;3559:27;3547:39;3444:142;3427:1543;;;3647:27;;:::i;:::-;3720:11;;3706:26;;3720:4;;3717:1;;3706:26;:10;:26;:::i;:::-;3678:102;;;;;;;;;;;;;;3803:23;;;3824:1;3803:23;;;;;;;;;3646:134;;-1:-1:-1;3803:23:1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;3794:32;;3852:5;3840:6;3847:1;3840:9;;;;;;;;;;;;;:17;;;;3427:1543;;;;3891:38;;;3903:26;3891:38;;:101;;-1:-1:-1;3945:47:1;;;3957:35;3945:47;3891:101;:163;;;-1:-1:-1;4008:46:1;;;4020:34;4008:46;3891:163;:217;;;-1:-1:-1;4070:38:1;;;4082:26;4070:38;3891:217;:280;;;-1:-1:-1;4124:47:1;;;4136:35;4124:47;3891:280;:335;;;-1:-1:-1;4187:39:1;;;4199:27;4187:39;3891:335;:399;;;-1:-1:-1;4242:48:1;;;4254:36;4242:48;3891:399;3874:1096;;;4439:11;;4425:26;;4439:4;;4436:1;;4425:26;:10;:26;:::i;:::-;4397:104;;;;;;;;;;;;;;4386:115;;3874:1096;;;4522:33;;;4534:21;4522:33;4518:452;;;4616:31;;:::i;:::-;4649:32;;:::i;:::-;4727:11;;4713:26;;4727:4;;4724:1;;4713:26;:10;:26;:::i;:::-;4685:118;;;;;;;;;;;;;;4865:23;;;4886:1;4865:23;;;;;;;;;4615:188;;-1:-1:-1;4615:188:1;;-1:-1:-1;4865:23:1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;4856:32;;4914:9;4902:6;4909:1;4902:9;;;;;;;;;;;;;:21;;;;4949:10;4937:6;4944:1;4937:9;;;;;;;;;;;;;:22;;;;4518:452;;;-1:-1:-1;3237:1762:1;;;:::o;1701:45:10:-;;;;:::o;8315:448:21:-;8399:13;8460:1;8449;:8;:12;8428:92;;;;;;;;;;;;;;8568:1;8581;8570;:8;:12;8568:15;;;;;;;;;;;;8682:8;;8678:16;;8707:17;;;-1:-1:-1;8568:15:21;;;;;;;8315:448::o;13292:490::-;13413:14;13476:5;13484:2;13476:10;13464:1;:8;:22;;13443:107;;;;;;;;;;;;;;-1:-1:-1;13729:13:21;13631:2;13729:13;13723:20;;13292:490::o;2245:1415:11:-;2479:16;;;;;2520;;2570:25;;;;;2994:11;;2979:13;;;2969:37;;;;3074:9;;1028:66;3097:26;;3223:15;;;3216:29;;;;3368:42;3349:62;;;3332:15;;;3325:87;;;;2459:17;3450:15;;3443:33;3617:3;3599:22;;;2245:1415::o;3216:204:10:-;3318:14;3355:58;3373:27;;3402:10;3355:17;:58::i;2604:1658:9:-;2857:29;;;;;2915:17;;2968:24;;;;;2821:33;3042:38;;;;3589:27;;3558:29;;;3548:69;;;;3685:9;;1121:66;3708:26;;3802:15;;;3795:33;;;;3883:15;;;3876:40;3971:15;;;3964:49;4080:3;4068:16;;4061:55;4219:3;4201:22;;2604:1658;;;:::o;2765:210:10:-;2870:14;2907:61;2925:30;;2957:10;2907:17;:61::i;5691:2759:1:-;6162:9;:21;;;;6141:82;;;;;;;;;;;;;;6265:23;6291:31;6310:11;6291:18;:31::i;:::-;6425:16;;;6439:1;6425:16;;;;;;;;;6479:25;;6265:57;;-1:-1:-1;6425:16:1;6479:25;6514:1147;6539:16;6534:1;:21;6514:1147;;6615:44;6662:29;6692:1;6662:32;;;;;;;;;;;;;;6615:79;;6708:35;;:::i;:::-;6746:266;;;;;;;;6794:8;6746:266;;;;;;6837:15;6746:266;;;;6892:20;6746:266;;;;6961:36;6746:266;;;6708:304;;7200:15;7161:36;:54;7074:191;;;;;;;;;;;;;;7344:20;7367:36;7394:8;7367:26;:36::i;:::-;7344:59;;7417:29;7449:53;7466:12;7480:18;7499:1;7480:21;;;;;;;;;;;;;;7449:16;:53::i;:::-;7417:85;-1:-1:-1;7597:53:1;:23;7417:85;7597:53;:30;:53;:::i;:::-;7571:79;-1:-1:-1;;6557:3:1;;;;;-1:-1:-1;6514:1147:1;;-1:-1:-1;;6514:1147:1;;-1:-1:-1;7773:41:1;:23;7804:9;7773:41;:30;:41;:::i;:::-;7848:13;;7747:67;;-1:-1:-1;7825:20:1;7871:573;7896:12;7891:1;:17;7871:573;;8042:1;8007:37;;:6;8014:1;8007:9;;;;;;;;;;;;;;:23;;;:37;;;8003:84;;;8064:8;;8003:84;8178:23;8204:6;8211:1;8204:9;;;;;;;;;;;;;;:29;;;8178:55;;8247:20;8270:49;8303:15;8270:23;:32;;:49;;;;:::i;:::-;8247:72;;8358:15;8333:100;;;;;;;;;;;;;;7871:573;;;7910:3;;7871:573;;;;5691:2759;;;;;;;;;;:::o;15595:687:21:-;15715:13;15777:5;15785:1;15777:9;15765:1;:8;:21;;15744:105;;;;;;;;;;;;;;-1:-1:-1;16023:13:21;15926:2;16023:13;16017:20;16176:66;16164:79;;15595:687::o;6453:617::-;6587:19;6651:2;6643:4;:10;;6622:83;;;;;;;;;;;;;;6742:1;:8;6736:2;:14;;6715:89;;;;;;;;;;;;;;6905:4;6900:2;:9;6890:20;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;6890:20:21;87:34:-1;135:17;;-1:-1;6890:20:21;;6881:29;;6920:120;6941:23;:6;:21;:23::i;:::-;6999:4;6978:18;:1;:16;:18::i;:::-;:25;7017:6;:13;6920:7;:120::i;:::-;6453:617;;;;;:::o;3701:890:10:-;4130:2;4124:9;4162:66;4147:82;;4279:1;4267:14;;4260:40;;;;4397:2;4385:15;;4378:35;4549:2;4531:21;;;3701:890::o;1089:2102:20:-;1437:19;;1586:4;1580:11;1208:16;;1437:12;;1509:2;:23;;;1675:45;;;;;;1437:19;1503:30;2075:32;;;;2054:102;;;;;;;;;;;;;;2410:18;2397:10;:31;2393:273;;;2444:78;2461:10;2473:20;2495:26;2444:16;:78::i;:::-;2579:10;2563:26;;2630:12;2606:36;;2545:111;2734:1;2712:23;;;;2775:2;2745:32;;;;2831:26;2808:20;:49;2787:70;;2880:18;2867:31;;2990:18;2976:12;2969:40;3071:10;3065:4;3058:24;3140:15;3101:12;3135:1;3114:18;:22;3101:36;;;;;;;;:54;;;;:36;;;;;;;;;;;:54;-1:-1:-1;3172:12:20;;1089:2102;-1:-1:-1;;;;;;1089:2102:20:o;3430:1034::-;3542:12;3685:2;3670:12;3664:19;3660:28;3798:2;3784:12;3780:21;3910:12;3890:18;3886:37;3984:18;3976:26;;3971:453;4010:16;4007:1;4004:23;3971:453;;;4129:1;4123:8;4225:12;4217:6;4214:24;4211:2;;;4315:1;4304:12;;4376:16;4371:21;;4211:2;;4041;4038:1;4034:10;4029:15;;3971:453;;;-1:-1:-1;;;3430:1034:20;;;;:::o;1341:228:21:-;1520:2;1509:14;;1341:228::o;1808:4337::-;1958:2;1949:6;:11;1945:4194;;;2247:1;2237:6;2233:2;2229:15;2224:3;2220:25;2216:33;2298:4;2294:9;2285:6;2279:13;2275:29;2347:4;2340;2334:11;2330:22;2388:1;2385;2382:8;2376:4;2369:22;;;;2186:219;;;2509:4;2499:6;:14;2495:59;;;2533:7;;2495:59;3243:4;3234:6;:13;3230:2899;;;3569:2;3561:6;3557:15;3547:25;;3617:6;3609;3605:19;3667:6;3661:4;3657:17;3974:4;3968:11;4242:198;4260:4;4252:6;4249:16;4242:198;;;4308:13;;4295:27;;4369:2;4405:13;;;;4357:15;;;;4242:198;;;4529:18;;-1:-1:-1;3276:1289:21;;;4810:2;4802:6;4798:15;4788:25;;4858:6;4850;4846:19;4908:6;4902:4;4898:17;5218:6;5212:13;5797:191;5814:4;5808;5804:15;5797:191;;;5862:11;;5849:25;;5907:13;;;;;5953;;;;5797:191;;;6078:19;;-1:-1:-1;;4612:1503:21;1808:4337;;;:::o;838:227:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;142:134:-1:-;220:13;;238:33;220:13;238:33;;299:693;;421:3;414:4;406:6;402:17;398:27;388:2;;-1:-1;;429:12;388:2;476:6;463:20;498:85;513:69;575:6;513:69;;;498:85;;;611:21;;;489:94;-1:-1;655:4;668:14;;;;643:17;;763:1;748:238;773:6;770:1;767:13;748:238;;;880:42;918:3;655:4;856:3;843:17;647:6;831:30;;880:42;;;868:55;;655:4;937:14;;;;965;;;;;795:1;788:9;748:238;;;752:14;;;;381:611;;;;;2646:432;;2743:3;2736:4;2728:6;2724:17;2720:27;2710:2;;-1:-1;;2751:12;2710:2;2798:6;2785:20;2820:60;2835:44;2872:6;2835:44;;2820:60;2811:69;;2900:6;2893:5;2886:21;3004:3;2936:4;2995:6;2928;2986:16;;2983:25;2980:2;;;3021:1;;3011:12;2980:2;37105:6;2936:4;2928:6;2924:17;2936:4;2962:5;2958:16;37082:30;37161:1;37143:16;;;2936:4;37143:16;37136:27;2962:5;2703:375;-1:-1;;2703:375;3087:434;;3195:3;3188:4;3180:6;3176:17;3172:27;3162:2;;-1:-1;;3203:12;3162:2;3243:6;3237:13;3265:60;3280:44;3317:6;3280:44;;3265:60;3256:69;;3345:6;3338:5;3331:21;3449:3;3381:4;3440:6;3373;3431:16;;3428:25;3425:2;;;3466:1;;3456:12;3425:2;3476:39;3508:6;3381:4;3407:5;3403:16;3381:4;3373:6;3369:17;3476:39;;;;3155:366;;;;;4981:2334;;5100:5;;5088:9;5083:3;5079:19;5075:31;5072:2;;;-1:-1;;5109:12;5072:2;5137:21;5152:5;5137:21;;;5128:30;;;5247:60;5303:3;5279:22;5247:60;;;5230:15;5223:85;5410:60;5466:3;5377:2;5446:9;5442:22;5410:60;;;5377:2;5396:5;5392:16;5385:86;5580:60;5636:3;5547:2;5616:9;5612:22;5580:60;;;5547:2;5566:5;5562:16;5555:86;5744:60;5800:3;5711:2;5780:9;5776:22;5744:60;;;5711:2;5730:5;5726:16;5719:86;5878:3;5948:9;5944:22;8315:13;5878:3;5898:5;5894:16;5887:86;6046:3;6116:9;6112:22;8315:13;6046:3;6066:5;6062:16;6055:86;6206:3;6276:9;6272:22;8315:13;6206:3;6226:5;6222:16;6215:86;6366:3;6436:9;6432:22;8315:13;6366:3;6386:5;6382:16;6375:86;6539:3;6621:6;6610:9;6606:22;8315:13;6566:5;6559;6555:17;6548:87;;6696:3;6778:6;6767:9;6763:22;8315:13;6723:5;6716;6712:17;6705:87;;6884:3;;6873:9;6869:19;6863:26;6909:18;;6901:6;6898:30;6895:2;;;5216:1;;6931:12;6895:2;6977:65;7038:3;7029:6;7018:9;7014:22;6977:65;;;6969:5;6962;6958:17;6951:92;7135:3;;;;7124:9;7120:19;7114:26;7100:40;;7160:18;7152:6;7149:30;7146:2;;;5216:1;;7182:12;7146:2;;7228:65;7289:3;7280:6;7269:9;7265:22;7228:65;;;7220:5;7213;7209:17;7202:92;;;5066:2249;;;;;7374:719;;7497:4;7485:9;7480:3;7476:19;7472:30;7469:2;;;-1:-1;;7505:12;7469:2;7533:20;7497:4;7533:20;;;7524:29;;8180:6;8167:20;7617:15;7610:74;7754:2;7812:9;7808:22;72:20;97:33;124:5;97:33;;;7754:2;7769:16;;7762:75;7926:2;7911:18;;7898:32;7950:18;7939:30;;7936:2;;;7603:1;;7972:12;7936:2;8017:54;8067:3;8058:6;8047:9;8043:22;8017:54;;;7926:2;8003:5;7999:16;7992:80;;7463:630;;;;;8378:422;;8533:2;;8521:9;8512:7;8508:23;8504:32;8501:2;;;8549:1;8546;8539:12;8501:2;8590:17;8584:24;8628:18;8620:6;8617:30;8614:2;;;8660:1;8657;8650:12;8614:2;8767:6;8756:9;8752:22;1175:3;1168:4;1160:6;1156:17;1152:27;1142:2;;1193:1;1190;1183:12;1142:2;1223:6;1217:13;1203:27;;1245:95;1260:79;1332:6;1260:79;;1245:95;1368:21;;;1425:14;;;;1400:17;;;1511:10;1505:256;1530:6;1527:1;1524:13;1505:256;;;1630:67;1693:3;1412:4;1606:3;1600:10;1404:6;1588:23;;1630:67;;;1618:80;;1712:14;;;;1740;;;;1552:1;1545:9;1505:256;;;-1:-1;8670:114;;8495:305;-1:-1;;;;;;;;8495:305;8807:470;;;8937:2;8925:9;8916:7;8912:23;8908:32;8905:2;;;-1:-1;;8943:12;8905:2;2588:6;2575:20;8995:63;;9123:2;9112:9;9108:18;9095:32;9147:18;9139:6;9136:30;9133:2;;;-1:-1;;9169:12;9133:2;9199:62;9253:7;9244:6;9233:9;9229:22;9199:62;;;9189:72;;;8899:378;;;;;;9284:345;;9397:2;9385:9;9376:7;9372:23;9368:32;9365:2;;;-1:-1;;9403:12;9365:2;9461:17;9448:31;9499:18;9491:6;9488:30;9485:2;;;-1:-1;;9521:12;9485:2;9551:62;9605:7;9596:6;9585:9;9581:22;9551:62;;;9541:72;9359:270;-1:-1;;;;9359:270;9636:399;;9776:2;9764:9;9755:7;9751:23;9747:32;9744:2;;;9792:1;9789;9782:12;9744:2;9840:17;9827:31;9878:18;;9870:6;9867:30;9864:2;;;9910:1;9907;9900:12;9864:2;10002:6;9991:9;9987:22;4159:4;4147:9;4142:3;4138:19;4134:30;4131:2;;;4177:1;4174;4167:12;4131:2;4195:20;4159:4;4195:20;;;4186:29;;85:6;72:20;97:33;124:5;97:33;;;4276:74;;9776:2;4476:22;;;2575:20;4437:16;;;4430:75;4610:2;4595:18;;4582:32;4623:30;;;4620:2;;;4666:1;4663;4656:12;4620:2;4701:54;4751:3;4742:6;4731:9;4727:22;4701:54;;;4610:2;4683:16;;4676:80;-1:-1;4842:2;4896:22;;;8167:20;4857:16;;;4850:75;-1:-1;4687:5;9738:297;-1:-1;;;9738:297;10042:380;;10176:2;10164:9;10155:7;10151:23;10147:32;10144:2;;;-1:-1;;10182:12;10144:2;10233:17;10227:24;10271:18;10263:6;10260:30;10257:2;;;-1:-1;;10293:12;10257:2;10323:83;10398:7;10389:6;10378:9;10374:22;10323:83;;10429:633;;;10599:2;10587:9;10578:7;10574:23;10570:32;10567:2;;;-1:-1;;10605:12;10567:2;10656:17;10650:24;10694:18;;10686:6;10683:30;10680:2;;;-1:-1;;10716:12;10680:2;10746:83;10821:7;10812:6;10801:9;10797:22;10746:83;;;10736:93;;10887:2;10876:9;10872:18;10866:25;10852:39;;10911:18;10903:6;10900:30;10897:2;;;-1:-1;;10933:12;10897:2;;10963:83;11038:7;11029:6;11018:9;11014:22;10963:83;;11069:395;;11207:2;11195:9;11186:7;11182:23;11178:32;11175:2;;;-1:-1;;11213:12;11175:2;11271:17;11258:31;11309:18;11301:6;11298:30;11295:2;;;-1:-1;;11331:12;11295:2;11361:87;11440:7;11431:6;11420:9;11416:22;11361:87;;11471:1283;;;;;;11741:3;11729:9;11720:7;11716:23;11712:33;11709:2;;;11758:1;11755;11748:12;11709:2;11806:17;11793:31;11844:18;;11836:6;11833:30;11830:2;;;11876:1;11873;11866:12;11830:2;11896:87;11975:7;11966:6;11955:9;11951:22;11896:87;;;11886:97;;12020:2;;;;12063:9;12059:22;72:20;97:33;124:5;97:33;;;12028:63;-1:-1;12156:2;12141:18;;12128:32;12169:30;;;12166:2;;;12212:1;12209;12202:12;12166:2;12232:62;12286:7;12277:6;12266:9;12262:22;12232:62;;;12222:72;;;12359:2;12348:9;12344:18;12331:32;12383:18;12375:6;12372:30;12369:2;;;12415:1;12412;12405:12;12369:2;12496:6;12485:9;12481:22;1910:3;1903:4;1895:6;1891:17;1887:27;1877:2;;1928:1;1925;1918:12;1877:2;1965:6;1952:20;1938:34;;1987:80;2002:64;2059:6;2002:64;;1987:80;2095:21;;;2152:14;;;;2127:17;;;2241;;;2232:27;;;;2229:36;-1:-1;2226:2;;;2278:1;2275;2268:12;2226:2;2294:10;;;2288:206;2313:6;2310:1;2307:13;2288:206;;;8167:20;;2381:50;;2335:1;2328:9;;;;;2445:14;;;;2473;;2288:206;;;-1:-1;12425:88;-1:-1;;;;12578:3;12563:19;;12550:33;;-1:-1;12592:30;;;12589:2;;;12635:1;12632;12625:12;12589:2;;12655:83;12730:7;12721:6;12710:9;12706:22;12655:83;;;12645:93;;;11703:1051;;;;;;;;;13003:103;36801:42;36790:54;13064:37;;13058:48;14579:343;;14721:5;35317:12;35837:6;35832:3;35825:19;14814:52;14859:6;35874:4;35869:3;35865:14;35874:4;14840:5;14836:16;14814:52;;;37623:2;37603:14;37619:7;37599:28;14878:39;;;;35874:4;14878:39;;14669:253;-1:-1;;14669:253;24577:511;16636:66;16616:87;;16600:2;16722:12;;14371:37;;;;25051:12;;;24785:303;25095:213;36801:42;36790:54;;;;13064:37;;25213:2;25198:18;;25184:124;25315:437;;25521:2;;25510:9;25506:18;25561:20;25542:17;25535:47;25596:146;13542:5;35317:12;35837:6;35832:3;35825:19;35865:14;25510:9;35865:14;13554:112;;35865:14;13731:4;13723:6;13719:17;25510:9;13710:27;;13698:39;;35185:4;13827:5;35173:17;-1:-1;13866:387;13891:6;13888:1;13885:13;13866:387;;;13943:20;25510:9;13947:4;13943:20;;13938:3;13931:33;13998:6;13992:13;22086:5;22189:62;22237:13;22167:15;22161:22;22189:62;;;22338:4;22331:5;22327:16;22321:23;22350:63;22407:4;22402:3;22398:14;22384:12;22350:63;;;;35865:14;22500:5;22496:16;22490:23;22519:63;35865:14;22571:3;22567:14;22553:12;22519:63;;;;22670:4;22663:5;22659:16;22653:23;22682:63;22670:4;22734:3;22730:14;22716:12;22682:63;;;;22836:4;22829:5;22825:16;22819:23;22836:4;22900:3;22896:14;14371:37;23002:4;22995:5;22991:16;22985:23;23002:4;23066:3;23062:14;14371:37;23160:4;23153:5;23149:16;23143:23;23160:4;23224:3;23220:14;14371:37;23318:4;23311:5;23307:16;23301:23;23318:4;23382:3;23378:14;14371:37;23489:5;;23482;23478:17;23472:24;23559:5;23554:3;23550:15;14371:37;;23645:5;;23638;23634:17;23628:24;23715:5;23710:3;23706:15;14371:37;;23811:5;;23804;23800:17;23794:24;23855:14;23847:5;23842:3;23838:15;23831:39;23885:67;22086:5;22081:3;22077:15;23933:12;23885:67;;;23877:75;;;24047:5;;;;24040;24036:17;24030:24;24101:3;24095:4;24091:14;24083:5;24078:3;24074:15;24067:39;24121:67;24183:4;24169:12;24121:67;;;14012:110;-1:-1;;;14232:14;;;;-1:-1;;35173:17;;;;13913:1;13906:9;13866:387;;;-1:-1;25588:154;;25492:260;-1:-1;;;;;;;25492:260;25759:213;14371:37;;;25877:2;25862:18;;25848:124;25979:539;14371:37;;;37006:4;36995:16;;;;26338:2;26323:18;;24530:35;26421:2;26406:18;;14371:37;26504:2;26489:18;;14371:37;26177:3;26162:19;;26148:370;26525:407;26716:2;26730:47;;;15818:2;26701:18;;;35825:19;15854:66;35865:14;;;15834:87;15940:12;;;26687:245;26939:407;27130:2;27144:47;;;16191:2;27115:18;;;35825:19;16227:66;35865:14;;;16207:87;16313:12;;;27101:245;27353:407;27544:2;27558:47;;;16973:2;27529:18;;;35825:19;17009:66;35865:14;;;16989:87;17095:12;;;27515:245;27767:407;27958:2;27972:47;;;17346:2;27943:18;;;35825:19;17382:66;35865:14;;;17362:87;17468:12;;;27929:245;28181:407;28372:2;28386:47;;;17719:2;28357:18;;;35825:19;17755:66;35865:14;;;17735:87;17841:12;;;28343:245;28595:407;28786:2;28800:47;;;18092:2;28771:18;;;35825:19;18128:66;35865:14;;;18108:87;18214:12;;;28757:245;29009:407;29200:2;29214:47;;;18465:2;29185:18;;;35825:19;18501:66;35865:14;;;18481:87;18602:66;18588:12;;;18581:88;18688:12;;;29171:245;29423:407;29614:2;29628:47;;;18939:2;29599:18;;;35825:19;18975:66;35865:14;;;18955:87;19061:12;;;29585:245;29837:407;30028:2;30042:47;;;19312:2;30013:18;;;35825:19;19348:66;35865:14;;;19328:87;19434:12;;;29999:245;30251:407;30442:2;30456:47;;;19685:2;30427:18;;;35825:19;19721:66;35865:14;;;19701:87;19822:66;19808:12;;;19801:88;19908:12;;;30413:245;30665:407;30856:2;30870:47;;;20159:2;30841:18;;;35825:19;20195:66;35865:14;;;20175:87;20281:12;;;30827:245;31079:407;31270:2;31284:47;;;20532:2;31255:18;;;35825:19;20568:66;35865:14;;;20548:87;20654:12;;;31241:245;31493:407;31684:2;31698:47;;;20905:2;31669:18;;;35825:19;20941:66;35865:14;;;20921:87;21027:12;;;31655:245;31907:407;32098:2;32112:47;;;21278:2;32083:18;;;35825:19;21314:66;35865:14;;;21294:87;21415:66;21401:12;;;21394:88;21501:12;;;32069:245;32321:407;32512:2;32526:47;;;21752:2;32497:18;;;35825:19;21788:66;35865:14;;;21768:87;21874:12;;;32483:245;32735:707;;14401:5;14378:3;14371:37;36801:42;13094:5;36790:54;33134:2;33123:9;33119:18;13064:37;32969:3;33171:2;33160:9;33156:18;33149:48;33211:72;32969:3;32958:9;32954:19;33269:6;33211:72;;;33331:9;33325:4;33321:20;33316:2;33305:9;33301:18;33294:48;33356:76;33427:4;33418:6;33356:76;;;33348:84;32940:502;-1:-1;;;;;;;32940:502;33449:256;33511:2;33505:9;33537:17;;;33612:18;33597:34;;33633:22;;;33594:62;33591:2;;;33669:1;;33659:12;33591:2;33511;33678:22;33489:216;;-1:-1;33489:216;33712:263;;33876:18;33868:6;33865:30;33862:2;;;-1:-1;;33898:12;33862:2;-1:-1;33937:4;33925:17;;;33955:15;;33799:176;34527:254;;34666:18;34658:6;34655:30;34652:2;;;-1:-1;;34688:12;34652:2;-1:-1;34742:4;34719:17;34738:9;34715:33;34771:4;34761:15;;34589:192;37178:268;37243:1;37250:101;37264:6;37261:1;37258:13;37250:101;;;37331:11;;;37325:18;37312:11;;;37305:39;37286:2;37279:10;37250:101;;;37366:6;37363:1;37360:13;37357:2;;;37243:1;37422:6;37417:3;37413:16;37406:27;37357:2;;37227:219;;;;37640:117;36801:42;37727:5;36790:54;37702:5;37699:35;37689:2;;37748:1;;37738:12;37689:2;37683:74;" } } }, + "sources": { + "src/Coordinator.sol": { + "id": 0 + }, + "src/libs/LibConstants.sol": { + "id": 8 + }, + "src/interfaces/ITransactions.sol": { + "id": 7 + }, + "src/MixinSignatureValidator.sol": { + "id": 3 + }, + "@0x/contracts-utils/contracts/src/LibBytes.sol": { + "id": 21 + }, + "src/mixins/MSignatureValidator.sol": { + "id": 13 + }, + "src/interfaces/ISignatureValidator.sol": { + "id": 6 + }, + "src/MixinCoordinatorApprovalVerifier.sol": { + "id": 1 + }, + "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": { + "id": 18 + }, + "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": { + "id": 19 + }, + "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": { + "id": 17 + }, + "@0x/contracts-utils/contracts/src/LibAddressArray.sol": { + "id": 20 + }, + "src/libs/LibCoordinatorApproval.sol": { + "id": 9 + }, + "src/libs/LibEIP712Domain.sol": { + "id": 10 + }, + "src/libs/LibZeroExTransaction.sol": { + "id": 11 + }, + "src/mixins/MCoordinatorApprovalVerifier.sol": { + "id": 12 + }, + "src/interfaces/ICoordinatorApprovalVerifier.sol": { + "id": 4 + }, + "src/MixinCoordinatorCore.sol": { + "id": 2 + }, + "src/interfaces/ICoordinatorCore.sol": { + "id": 5 + } + }, + "sourceCodes": { + "src/Coordinator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibConstants.sol\";\nimport \"./MixinSignatureValidator.sol\";\nimport \"./MixinCoordinatorApprovalVerifier.sol\";\nimport \"./MixinCoordinatorCore.sol\";\n\n\n// solhint-disable no-empty-blocks\ncontract Coordinator is\n LibConstants,\n MixinSignatureValidator,\n MixinCoordinatorApprovalVerifier,\n MixinCoordinatorCore\n{\n constructor (address _exchange)\n public\n LibConstants(_exchange)\n {}\n}\n", + "src/libs/LibConstants.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ITransactions.sol\";\n\n\ncontract LibConstants {\n\n // solhint-disable-next-line var-name-mixedcase\n ITransactions internal EXCHANGE;\n\n constructor (address _exchange)\n public\n {\n EXCHANGE = ITransactions(_exchange);\n }\n}\n", + "src/interfaces/ITransactions.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\npragma solidity ^0.5.5;\n\n\ncontract ITransactions {\n\n /// @dev Executes an exchange method call in the context of signer.\n /// @param salt Arbitrary number to ensure uniqueness of transaction hash.\n /// @param signerAddress Address of transaction signer.\n /// @param data AbiV2 encoded calldata.\n /// @param signature Proof of signer transaction by signer.\n function executeTransaction(\n uint256 salt,\n address signerAddress,\n bytes calldata data,\n bytes calldata signature\n )\n external;\n}\n", + "src/MixinSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\n\n\ncontract MixinSignatureValidator is\n MSignatureValidator\n{\n using LibBytes for bytes;\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress)\n {\n require(\n signature.length > 0,\n \"LENGTH_GREATER_THAN_0_REQUIRED\"\n );\n\n // Pop last byte off of signature byte array.\n uint8 signatureTypeRaw = uint8(signature.popLastByte());\n\n // Ensure signature is supported\n require(\n signatureTypeRaw < uint8(SignatureType.NSignatureTypes),\n \"SIGNATURE_UNSUPPORTED\"\n );\n\n SignatureType signatureType = SignatureType(signatureTypeRaw);\n\n // Always illegal signature.\n // This is always an implicit option since a signer can create a\n // signature array with invalid type or length. We may as well make\n // it an explicit option. This aids testing and analysis. It is\n // also the initialization value for the enum type.\n if (signatureType == SignatureType.Illegal) {\n revert(\"SIGNATURE_ILLEGAL\");\n\n // Always invalid signature.\n // Like Illegal, this is always implicitly available and therefore\n // offered explicitly. It can be implicitly created by providing\n // a correctly formatted but incorrect signature.\n } else if (signatureType == SignatureType.Invalid) {\n require(\n signature.length == 0,\n \"LENGTH_0_REQUIRED\"\n );\n revert(\"SIGNATURE_INVALID\");\n\n // Signature using EIP712\n } else if (signatureType == SignatureType.EIP712) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n hash,\n v,\n r,\n s\n );\n return signerAddress;\n\n // Signed using web3.eth_sign\n } else if (signatureType == SignatureType.EthSign) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n keccak256(abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n32\",\n hash\n )),\n v,\n r,\n s\n );\n return signerAddress;\n }\n\n // Anything else is illegal (We do not return false because\n // the signature may actually be valid, just not in a format\n // that we currently support. In this case returning false\n // may lead the caller to incorrectly believe that the\n // signature was invalid.)\n revert(\"SIGNATURE_UNSUPPORTED\");\n }\n}\n", + "@0x/contracts-utils/contracts/src/LibBytes.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\nlibrary LibBytes {\n\n using LibBytes for bytes;\n\n /// @dev Gets the memory address for a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of byte array. This\n /// points to the header of the byte array which contains\n /// the length.\n function rawAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := input\n }\n return memoryAddress;\n }\n \n /// @dev Gets the memory address for the contents of a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of the contents of the byte array.\n function contentAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := add(input, 32)\n }\n return memoryAddress;\n }\n\n /// @dev Copies `length` bytes from memory location `source` to `dest`.\n /// @param dest memory address to copy bytes to.\n /// @param source memory address to copy bytes from.\n /// @param length number of bytes to copy.\n function memCopy(\n uint256 dest,\n uint256 source,\n uint256 length\n )\n internal\n pure\n {\n if (length < 32) {\n // Handle a partial word by reading destination and masking\n // off the bits we are interested in.\n // This correctly handles overlap, zero lengths and source == dest\n assembly {\n let mask := sub(exp(256, sub(32, length)), 1)\n let s := and(mload(source), not(mask))\n let d := and(mload(dest), mask)\n mstore(dest, or(s, d))\n }\n } else {\n // Skip the O(length) loop when source == dest.\n if (source == dest) {\n return;\n }\n\n // For large copies we copy whole words at a time. The final\n // word is aligned to the end of the range (instead of after the\n // previous) to handle partial words. So a copy will look like this:\n //\n // ####\n // ####\n // ####\n // ####\n //\n // We handle overlap in the source and destination range by\n // changing the copying direction. This prevents us from\n // overwriting parts of source that we still need to copy.\n //\n // This correctly handles source == dest\n //\n if (source > dest) {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because it\n // is easier to compare with in the loop, and these\n // are also the addresses we need for copying the\n // last bytes.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the last 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the last bytes in\n // source already due to overlap.\n let last := mload(sEnd)\n\n // Copy whole words front to back\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} lt(source, sEnd) {} {\n mstore(dest, mload(source))\n source := add(source, 32)\n dest := add(dest, 32)\n }\n \n // Write the last 32 bytes\n mstore(dEnd, last)\n }\n } else {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because those\n // are the starting points when copying a word at the end.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the first 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the first bytes in\n // source already due to overlap.\n let first := mload(source)\n\n // Copy whole words back to front\n // We use a signed comparisson here to allow dEnd to become\n // negative (happens when source and dest < 32). Valid\n // addresses in local memory will never be larger than\n // 2**255, so they can be safely re-interpreted as signed.\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} slt(dest, dEnd) {} {\n mstore(dEnd, mload(sEnd))\n sEnd := sub(sEnd, 32)\n dEnd := sub(dEnd, 32)\n }\n \n // Write the first 32 bytes\n mstore(dest, first)\n }\n }\n }\n }\n\n /// @dev Returns a slices from a byte array.\n /// @param b The byte array to take a slice from.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n function slice(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure and copy contents\n result = new bytes(to - from);\n memCopy(\n result.contentAddress(),\n b.contentAddress() + from,\n result.length\n );\n return result;\n }\n \n /// @dev Returns a slice from a byte array without preserving the input.\n /// @param b The byte array to take a slice from. Will be destroyed in the process.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted.\n function sliceDestructive(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure around [from, to) in-place.\n assembly {\n result := add(b, from)\n mstore(result, sub(to, from))\n }\n return result;\n }\n\n /// @dev Pops the last byte off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The byte that was popped off.\n function popLastByte(bytes memory b)\n internal\n pure\n returns (bytes1 result)\n {\n require(\n b.length > 0,\n \"GREATER_THAN_ZERO_LENGTH_REQUIRED\"\n );\n\n // Store last byte.\n result = b[b.length - 1];\n\n assembly {\n // Decrement length of byte array.\n let newLen := sub(mload(b), 1)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Pops the last 20 bytes off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The 20 byte address that was popped off.\n function popLast20Bytes(bytes memory b)\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= 20,\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Store last 20 bytes.\n result = readAddress(b, b.length - 20);\n\n assembly {\n // Subtract 20 from byte array length.\n let newLen := sub(mload(b), 20)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Tests equality of two byte arrays.\n /// @param lhs First byte array to compare.\n /// @param rhs Second byte array to compare.\n /// @return True if arrays are the same. False otherwise.\n function equals(\n bytes memory lhs,\n bytes memory rhs\n )\n internal\n pure\n returns (bool equal)\n {\n // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare.\n // We early exit on unequal lengths, but keccak would also correctly\n // handle this.\n return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs);\n }\n\n /// @dev Reads an address from a position in a byte array.\n /// @param b Byte array containing an address.\n /// @param index Index in byte array of address.\n /// @return address from byte array.\n function readAddress(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Read address from array memory\n assembly {\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 20-byte mask to obtain address\n result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n return result;\n }\n\n /// @dev Writes an address into a specific position in a byte array.\n /// @param b Byte array to insert address into.\n /// @param index Index in byte array of address.\n /// @param input Address to put into byte array.\n function writeAddress(\n bytes memory b,\n uint256 index,\n address input\n )\n internal\n pure\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Store address into array memory\n assembly {\n // The address occupies 20 bytes and mstore stores 32 bytes.\n // First fetch the 32-byte word where we'll be storing the address, then\n // apply a mask so we have only the bytes in the word that the address will not occupy.\n // Then combine these bytes with the address and store the 32 bytes back to memory with mstore.\n\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address\n let neighbors := and(\n mload(add(b, index)),\n 0xffffffffffffffffffffffff0000000000000000000000000000000000000000\n )\n \n // Make sure input address is clean.\n // (Solidity does not guarantee this)\n input := and(input, 0xffffffffffffffffffffffffffffffffffffffff)\n\n // Store the neighbors and address into memory\n mstore(add(b, index), xor(input, neighbors))\n }\n }\n\n /// @dev Reads a bytes32 value from a position in a byte array.\n /// @param b Byte array containing a bytes32 value.\n /// @param index Index in byte array of bytes32 value.\n /// @return bytes32 value from byte array.\n function readBytes32(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes32 result)\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n result := mload(add(b, index))\n }\n return result;\n }\n\n /// @dev Writes a bytes32 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes32 to put into byte array.\n function writeBytes32(\n bytes memory b,\n uint256 index,\n bytes32 input\n )\n internal\n pure\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n mstore(add(b, index), input)\n }\n }\n\n /// @dev Reads a uint256 value from a position in a byte array.\n /// @param b Byte array containing a uint256 value.\n /// @param index Index in byte array of uint256 value.\n /// @return uint256 value from byte array.\n function readUint256(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (uint256 result)\n {\n result = uint256(readBytes32(b, index));\n return result;\n }\n\n /// @dev Writes a uint256 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input uint256 to put into byte array.\n function writeUint256(\n bytes memory b,\n uint256 index,\n uint256 input\n )\n internal\n pure\n {\n writeBytes32(b, index, bytes32(input));\n }\n\n /// @dev Reads an unpadded bytes4 value from a position in a byte array.\n /// @param b Byte array containing a bytes4 value.\n /// @param index Index in byte array of bytes4 value.\n /// @return bytes4 value from byte array.\n function readBytes4(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes4 result)\n {\n require(\n b.length >= index + 4,\n \"GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 32 byte length field\n index += 32;\n\n // Read the bytes4 from array memory\n assembly {\n result := mload(add(b, index))\n // Solidity does not require us to clean the trailing bytes.\n // We do it anyway\n result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)\n }\n return result;\n }\n\n /// @dev Reads nested bytes from a specific position.\n /// @dev NOTE: the returned value overlaps with the input value.\n /// Both should be treated as immutable.\n /// @param b Byte array containing nested bytes.\n /// @param index Index of nested bytes.\n /// @return result Nested bytes.\n function readBytesWithLength(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes memory result)\n {\n // Read length of nested bytes\n uint256 nestedBytesLength = readUint256(b, index);\n index += 32;\n\n // Assert length of is valid, given\n // length of nested bytes\n require(\n b.length >= index + nestedBytesLength,\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n \n // Return a pointer to the byte array as it exists inside `b`\n assembly {\n result := add(b, index)\n }\n return result;\n }\n\n /// @dev Inserts bytes at a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes to insert.\n function writeBytesWithLength(\n bytes memory b,\n uint256 index,\n bytes memory input\n )\n internal\n pure\n {\n // Assert length of is valid, given\n // length of input\n require(\n b.length >= index + 32 + input.length, // 32 bytes to store length\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n\n // Copy into \n memCopy(\n b.contentAddress() + index,\n input.rawAddress(), // includes length of \n input.length + 32 // +32 bytes to store length\n );\n }\n\n /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.\n /// @param dest Byte array that will be overwritten with source bytes.\n /// @param source Byte array to copy onto dest bytes.\n function deepCopyBytes(\n bytes memory dest,\n bytes memory source\n )\n internal\n pure\n {\n uint256 sourceLen = source.length;\n // Dest length must be >= source length, or some bytes would not be copied.\n require(\n dest.length >= sourceLen,\n \"GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED\"\n );\n memCopy(\n dest.contentAddress(),\n source.contentAddress(),\n sourceLen\n );\n }\n}\n", + "src/mixins/MSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ISignatureValidator.sol\";\n\n\ncontract MSignatureValidator is\n ISignatureValidator\n{\n // Allowed signature types.\n enum SignatureType {\n Illegal, // 0x00, default value\n Invalid, // 0x01\n EIP712, // 0x02\n EthSign, // 0x03\n NSignatureTypes // 0x04, number of signature types. Always leave at end.\n }\n}\n", + "src/interfaces/ISignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract ISignatureValidator {\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress);\n}\n", + "src/MixinCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol\";\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibAddressArray.sol\";\nimport \"./libs/LibCoordinatorApproval.sol\";\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\n\n\n// solhint-disable avoid-tx-origin\ncontract MixinCoordinatorApprovalVerifier is\n LibExchangeSelectors,\n LibCoordinatorApproval,\n LibZeroExTransaction,\n MSignatureValidator,\n MCoordinatorApprovalVerifier\n{\n using LibBytes for bytes;\n using LibAddressArray for address[];\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view\n {\n // Get the orders from the the Exchange calldata in the 0x transaction\n LibOrder.Order[] memory orders = decodeOrdersFromFillData(transaction.data);\n\n // No approval is required for non-fill methods\n if (orders.length > 0) {\n // Revert if approval is invalid for transaction orders\n assertValidTransactionOrdersApproval(\n transaction,\n orders,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n }\n }\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders)\n {\n bytes4 selector = data.readBytes4(0);\n if (\n selector == FILL_ORDER_SELECTOR ||\n selector == FILL_ORDER_NO_THROW_SELECTOR ||\n selector == FILL_OR_KILL_ORDER_SELECTOR\n ) {\n // Decode single order\n (LibOrder.Order memory order) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order)\n );\n orders = new LibOrder.Order[](1);\n orders[0] = order;\n } else if (\n selector == BATCH_FILL_ORDERS_SELECTOR ||\n selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||\n selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||\n selector == MARKET_SELL_ORDERS_SELECTOR ||\n selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR\n ) {\n // Decode all orders\n // solhint-disable indent\n (orders) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order[])\n );\n } else if (selector == MATCH_ORDERS_SELECTOR) {\n // Decode left and right orders\n (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order, LibOrder.Order)\n );\n\n // Create array of orders\n orders = new LibOrder.Order[](2);\n orders[0] = leftOrder;\n orders[1] = rightOrder;\n }\n return orders;\n }\n\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view\n {\n // Verify that Ethereum tx signer is the same as the approved txOrigin\n require(\n tx.origin == txOrigin,\n \"INVALID_ORIGIN\"\n );\n\n // Hash 0x transaction\n bytes32 transactionHash = getTransactionHash(transaction);\n\n // Create empty list of approval signers\n address[] memory approvalSignerAddresses = new address[](0);\n\n uint256 signaturesLength = approvalSignatures.length;\n for (uint256 i = 0; i != signaturesLength; i++) {\n // Create approval message\n uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i];\n CoordinatorApproval memory approval = CoordinatorApproval({\n txOrigin: txOrigin,\n transactionHash: transactionHash,\n transactionSignature: transactionSignature,\n approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds\n });\n\n // Ensure approval has not expired\n require(\n // solhint-disable-next-line not-rely-on-time\n currentApprovalExpirationTimeSeconds > block.timestamp,\n \"APPROVAL_EXPIRED\"\n );\n\n // Hash approval message and recover signer address\n bytes32 approvalHash = getCoordinatorApprovalHash(approval);\n address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]);\n\n // Add approval signer to list of signers\n approvalSignerAddresses = approvalSignerAddresses.append(approvalSignerAddress);\n }\n\n // Ethereum transaction signer gives implicit signature of approval\n approvalSignerAddresses = approvalSignerAddresses.append(tx.origin);\n\n uint256 ordersLength = orders.length;\n for (uint256 i = 0; i != ordersLength; i++) {\n // Do not check approval if the order's senderAddress is null\n if (orders[i].senderAddress == address(0)) {\n continue;\n }\n\n // Ensure feeRecipient of order has approved this 0x transaction\n address approverAddress = orders[i].feeRecipientAddress;\n bool isOrderApproved = approvalSignerAddresses.contains(approverAddress);\n require(\n isOrderApproved,\n \"INVALID_APPROVAL_SIGNATURE\"\n );\n }\n }\n}\n", + "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibExchangeSelectors {\n\n // solhint-disable max-line-length\n // allowedValidators\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514;\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256(\"allowedValidators(address,address)\"));\n\n // assetProxies\n bytes4 constant internal ASSET_PROXIES_SELECTOR = 0x3fd3c997;\n bytes4 constant internal ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256(\"assetProxies(bytes4)\"));\n\n // batchCancelOrders\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782;\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // batchFillOrKillOrders\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546;\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrders\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b;\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrdersNoThrow\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190;\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // cancelOrder\n bytes4 constant internal CANCEL_ORDER_SELECTOR = 0xd46b02c3;\n bytes4 constant internal CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // cancelOrdersUpTo\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1;\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrdersUpTo(uint256)\"));\n\n // cancelled\n bytes4 constant internal CANCELLED_SELECTOR = 0x2ac12622;\n bytes4 constant internal CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelled(bytes32)\"));\n\n // currentContextAddress\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba;\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256(\"currentContextAddress()\"));\n\n // executeTransaction\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce;\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256(\"executeTransaction(uint256,address,bytes,bytes)\"));\n\n // fillOrKillOrder\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15;\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrder\n bytes4 constant internal FILL_ORDER_SELECTOR = 0xb4be83d5;\n bytes4 constant internal FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrderNoThrow\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae;\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // filled\n bytes4 constant internal FILLED_SELECTOR = 0x288cdc91;\n bytes4 constant internal FILLED_SELECTOR_GENERATOR = bytes4(keccak256(\"filled(bytes32)\"));\n\n // getAssetProxy\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR = 0x60704108;\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"getAssetProxy(bytes4)\"));\n\n // getOrderInfo\n bytes4 constant internal GET_ORDER_INFO_SELECTOR = 0xc75e0a81;\n bytes4 constant internal GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // getOrdersInfo\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc;\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // isValidSignature\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR = 0x93634702;\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256(\"isValidSignature(bytes32,address,bytes)\"));\n\n // marketBuyOrders\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b;\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketBuyOrdersNoThrow\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380;\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrders\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808;\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrdersNoThrow\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18;\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // matchOrders\n bytes4 constant internal MATCH_ORDERS_SELECTOR = 0x3c28d861;\n bytes4 constant internal MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)\"));\n\n // orderEpoch\n bytes4 constant internal ORDER_EPOCH_SELECTOR = 0xd9bfa73e;\n bytes4 constant internal ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256(\"orderEpoch(address,address)\"));\n\n // owner\n bytes4 constant internal OWNER_SELECTOR = 0x8da5cb5b;\n bytes4 constant internal OWNER_SELECTOR_GENERATOR = bytes4(keccak256(\"owner()\"));\n\n // preSign\n bytes4 constant internal PRE_SIGN_SELECTOR = 0x3683ef8e;\n bytes4 constant internal PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256(\"preSign(bytes32,address,bytes)\"));\n\n // preSigned\n bytes4 constant internal PRE_SIGNED_SELECTOR = 0x82c174d0;\n bytes4 constant internal PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256(\"preSigned(bytes32,address)\"));\n\n // registerAssetProxy\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93;\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"registerAssetProxy(address)\"));\n\n // setSignatureValidatorApproval\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68;\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256(\"setSignatureValidatorApproval(address,bool)\"));\n\n // transactions\n bytes4 constant internal TRANSACTIONS_SELECTOR = 0x642f2eaf;\n bytes4 constant internal TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256(\"transactions(bytes32)\"));\n\n // transferOwnership\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256(\"transferOwnership(address)\"));\n}", + "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibEIP712.sol\";\n\n\ncontract LibOrder is\n LibEIP712\n{\n // Hash for the EIP712 Order Schema\n bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"Order(\",\n \"address makerAddress,\",\n \"address takerAddress,\",\n \"address feeRecipientAddress,\",\n \"address senderAddress,\",\n \"uint256 makerAssetAmount,\",\n \"uint256 takerAssetAmount,\",\n \"uint256 makerFee,\",\n \"uint256 takerFee,\",\n \"uint256 expirationTimeSeconds,\",\n \"uint256 salt,\",\n \"bytes makerAssetData,\",\n \"bytes takerAssetData\",\n \")\"\n ));\n\n // A valid order remains fillable until it is expired, fully filled, or cancelled.\n // An order's state is unaffected by external factors, like account balances.\n enum OrderStatus {\n INVALID, // Default value\n INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount\n INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount\n FILLABLE, // Order is fillable\n EXPIRED, // Order has already expired\n FULLY_FILLED, // Order is fully filled\n CANCELLED // Order has been cancelled\n }\n\n // solhint-disable max-line-length\n struct Order {\n address makerAddress; // Address that created the order. \n address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order. \n address feeRecipientAddress; // Address that will recieve fees when order is filled. \n address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.\n uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0. \n uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0. \n uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.\n uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.\n uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires. \n uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash. \n bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.\n bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.\n }\n // solhint-enable max-line-length\n\n struct OrderInfo {\n uint8 orderStatus; // Status that describes order's validity and fillability.\n bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash).\n uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.\n }\n\n /// @dev Calculates Keccak-256 hash of the order.\n /// @param order The order structure.\n /// @return Keccak-256 EIP712 hash of the order.\n function getOrderHash(Order memory order)\n internal\n view\n returns (bytes32 orderHash)\n {\n orderHash = hashEIP712Message(hashOrder(order));\n return orderHash;\n }\n\n /// @dev Calculates EIP712 hash of the order.\n /// @param order The order structure.\n /// @return EIP712 hash of the order.\n function hashOrder(Order memory order)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;\n bytes32 makerAssetDataHash = keccak256(order.makerAssetData);\n bytes32 takerAssetDataHash = keccak256(order.takerAssetData);\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ORDER_SCHEMA_HASH,\n // bytes32(order.makerAddress),\n // bytes32(order.takerAddress),\n // bytes32(order.feeRecipientAddress),\n // bytes32(order.senderAddress),\n // order.makerAssetAmount,\n // order.takerAssetAmount,\n // order.makerFee,\n // order.takerFee,\n // order.expirationTimeSeconds,\n // order.salt,\n // keccak256(order.makerAssetData),\n // keccak256(order.takerAssetData)\n // ));\n\n assembly {\n // Calculate memory addresses that will be swapped out before hashing\n let pos1 := sub(order, 32)\n let pos2 := add(order, 320)\n let pos3 := add(order, 352)\n\n // Backup\n let temp1 := mload(pos1)\n let temp2 := mload(pos2)\n let temp3 := mload(pos3)\n \n // Hash in place\n mstore(pos1, schemaHash)\n mstore(pos2, makerAssetDataHash)\n mstore(pos3, takerAssetDataHash)\n result := keccak256(pos1, 416)\n \n // Restore\n mstore(pos1, temp1)\n mstore(pos2, temp2)\n mstore(pos3, temp3)\n }\n return result;\n }\n}\n", + "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibEIP712 {\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value\n string constant internal EIP712_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value\n string constant internal EIP712_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_DOMAIN_NAME)),\n keccak256(bytes(EIP712_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712Message(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;\n\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct \n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", + "@0x/contracts-utils/contracts/src/LibAddressArray.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibBytes.sol\";\n\n\nlibrary LibAddressArray {\n\n /// @dev Append a new address to an array of addresses.\n /// The `addressArray` may need to be reallocated to make space\n /// for the new address. Because of this we return the resulting\n /// memory location of `addressArray`.\n /// @param addressArray Array of addresses.\n /// @param addressToAppend Address to append.\n /// @return Array of addresses: [... addressArray, addressToAppend]\n function append(address[] memory addressArray, address addressToAppend)\n internal\n pure\n returns (address[] memory)\n {\n // Get stats on address array and free memory\n uint256 freeMemPtr = 0;\n uint256 addressArrayBeginPtr = 0;\n uint256 addressArrayEndPtr = 0;\n uint256 addressArrayLength = addressArray.length;\n uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);\n assembly {\n freeMemPtr := mload(0x40)\n addressArrayBeginPtr := addressArray\n addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)\n }\n\n // Cases for `freeMemPtr`:\n // `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`\n // `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`\n // `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.\n require(\n freeMemPtr >= addressArrayEndPtr,\n \"INVALID_FREE_MEMORY_PTR\"\n );\n\n // If free memory begins at the end of `addressArray`\n // then we can append `addressToAppend` directly.\n // Otherwise, we must copy the array to free memory\n // before appending new values to it.\n if (freeMemPtr > addressArrayEndPtr) {\n LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);\n assembly {\n addressArray := freeMemPtr\n addressArrayBeginPtr := addressArray\n }\n }\n\n // Append `addressToAppend`\n addressArrayLength += 1;\n addressArrayMemSizeInBytes += 32;\n addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;\n freeMemPtr = addressArrayEndPtr;\n assembly {\n // Store new array length\n mstore(addressArray, addressArrayLength)\n\n // Update `freeMemPtr`\n mstore(0x40, freeMemPtr)\n }\n addressArray[addressArrayLength - 1] = addressToAppend;\n return addressArray;\n }\n\n /// @dev Checks if an address array contains the target address.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return True if the addressArray contains the target.\n function contains(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success to true\n success := 1\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return success;\n }\n\n /// @dev Finds the index of an address within an array.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return Existence and index of the target in the array.\n function indexOf(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success, uint256 index)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success and index\n success := 1\n index := div(sub(i, arrayContentsStart), 32)\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return (success, index);\n }\n}\n", + "src/libs/LibCoordinatorApproval.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibCoordinatorApproval is\n LibEIP712Domain\n{\n // Hash for the EIP712 Coordinator approval message\n // keccak256(abi.encodePacked(\n // \"CoordinatorApproval(\",\n // \"address txOrigin,\",\n // \"bytes32 transactionHash,\",\n // \"bytes transactionSignature,\",\n // \"uint256 approvalExpirationTimeSeconds\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05;\n\n struct CoordinatorApproval {\n address txOrigin; // Required signer of Ethereum transaction that is submitting approval.\n bytes32 transactionHash; // EIP712 hash of the transaction.\n bytes transactionSignature; // Signature of the 0x transaction.\n uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the approval expires.\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.\n function getCoordinatorApprovalHash(CoordinatorApproval memory approval)\n public\n view\n returns (bytes32 approvalHash)\n {\n approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval));\n return approvalHash;\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage with no domain separator.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with no domain separator.\n function hashCoordinatorApproval(CoordinatorApproval memory approval)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH;\n bytes memory transactionSignature = approval.transactionSignature;\n address txOrigin = approval.txOrigin;\n bytes32 transactionHash = approval.transactionHash;\n uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH,\n // approval.txOrigin,\n // approval.transactionHash,\n // keccak256(approval.transactionSignature)\n // approval.approvalExpirationTimeSeconds,\n // ));\n\n assembly {\n // Compute hash of transaction signature\n let transactionSignatureHash := keccak256(add(transactionSignature, 32), mload(transactionSignature))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), txOrigin) // txOrigin\n mstore(add(memPtr, 64), transactionHash) // transactionHash\n mstore(add(memPtr, 96), transactionSignatureHash) // transactionSignatureHash\n mstore(add(memPtr, 128), approvalExpirationTimeSeconds) // approvalExpirationTimeSeconds\n // Compute hash\n result := keccak256(memPtr, 160)\n }\n return result;\n }\n}\n", + "src/libs/LibEIP712Domain.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibConstants.sol\";\n\n\ncontract LibEIP712Domain is\n LibConstants\n{\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_NAME = \"0x Protocol Coordinator\";\n\n // EIP712 Domain Version value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = \"1.0.0\";\n\n // EIP712 Domain Name value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data for the Coordinator\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;\n\n // Hash of the EIP712 Domain Separator data for the Exchange\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)),\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n\n EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)),\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)),\n uint256(address(EXCHANGE))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of this contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712CoordinatorMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of the Exchange contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712ExchangeMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.\n /// @param eip712DomainHash Hash of the domain domain separator data.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)\n internal\n pure\n returns (bytes32 result)\n {\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct\n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", + "src/libs/LibZeroExTransaction.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibZeroExTransaction is\n LibEIP712Domain\n{\n // Hash for the EIP712 0x transaction schema\n // keccak256(abi.encodePacked(\n // \"ZeroExTransaction(\",\n // \"uint256 salt,\",\n // \"address signerAddress,\",\n // \"bytes data\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0x213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c;\n\n struct ZeroExTransaction {\n uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash.\n address signerAddress; // Address of transaction signer.\n bytes data; // AbiV2 encoded calldata.\n }\n\n /// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with the domain separator of this contract.\n function getTransactionHash(ZeroExTransaction memory transaction)\n public\n view\n returns (bytes32 transactionHash)\n {\n // Hash the transaction with the domain separator of the Exchange contract.\n transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction));\n return transactionHash;\n }\n\n /// @dev Calculates EIP712 hash of the 0x transaction with no domain separator.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with no domain separator.\n function hashZeroExTransaction(ZeroExTransaction memory transaction)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;\n bytes memory data = transaction.data;\n uint256 salt = transaction.salt;\n address signerAddress = transaction.signerAddress;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,\n // transaction.salt,\n // uint256(transaction.signerAddress),\n // keccak256(transaction.data)\n // ));\n\n assembly {\n // Compute hash of data\n let dataHash := keccak256(add(data, 32), mload(data))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), salt) // salt\n mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress\n mstore(add(memPtr, 96), dataHash) // hash of data\n\n // Compute hash\n result := keccak256(memPtr, 128)\n }\n return result;\n }\n}\n", + "src/mixins/MCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../interfaces/ICoordinatorApprovalVerifier.sol\";\n\n\ncontract MCoordinatorApprovalVerifier is\n ICoordinatorApprovalVerifier\n{\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view;\n}\n", + "src/interfaces/ICoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorApprovalVerifier {\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view;\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders);\n}\n", + "src/MixinCoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./libs/LibConstants.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\nimport \"./interfaces/ICoordinatorCore.sol\";\n\n\ncontract MixinCoordinatorCore is\n LibConstants,\n MCoordinatorApprovalVerifier,\n ICoordinatorCore\n{\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n {\n // Validate that the 0x transaction has been approves by each feeRecipient\n assertValidCoordinatorApprovals(\n transaction,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n\n // Execute the transaction\n EXCHANGE.executeTransaction(\n transaction.salt,\n transaction.signerAddress,\n transaction.data,\n transactionSignature\n );\n }\n}\n", + "src/interfaces/ICoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorCore {\n\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public;\n}\n" + }, + "sourceTreeHashHex": "0xcd3a1dbf858b46a5820dab320baad978613f07ec73d35b6cbbde13c2937bbc04", + "compiler": { + "name": "solc", + "version": "soljson-v0.5.8+commit.23d335f2.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { + "yul": true, + "deduplicate": true, + "cse": true, + "constantOptimizer": true + } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "constantinople", + "remappings": [ + "@0x/contracts-utils=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-utils", + "@0x/contracts-exchange-libs=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-exchange-libs" + ] + } + }, "networks": {} -} +} \ No newline at end of file diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 075221dae0..1eaf2cf7ce 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -28,7 +28,7 @@ const anotherCoordinatorPort = '4000'; const coordinatorEndpoint = 'http://localhost:'; // tslint:disable:custom-no-magic-numbers -describe.only('CoordinatorWrapper', () => { +describe('CoordinatorWrapper', () => { const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); let coordinatorServerApp: http.Server; @@ -273,7 +273,7 @@ describe.only('CoordinatorWrapper', () => { // fill handling is the same for all fill methods so we can test them all through the fillOrder and batchFillOrders interfaces describe('fill order(s)', () => { describe('#fillOrderAsync', () => { - it.only('should fill a valid order', async () => { + it('should fill a valid order', async () => { txHash = await contractWrappers.coordinator.fillOrderAsync( signedOrder, takerTokenFillAmount, From 058a6fb2bfbbaeeecff1604f96f3fac9b18945fd Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 17:21:30 -0700 Subject: [PATCH 23/53] remove repeated code --- .../contract_wrappers/coordinator_wrapper.ts | 79 +++++++------------ 1 file changed, 29 insertions(+), 50 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 6016cdd383..2e379150d0 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -434,30 +434,14 @@ export class CoordinatorWrapper extends ContractWrapper { assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); const data = this._transactionEncoder.batchCancelOrdersTx(orders); - // create lookup tables to match server endpoints to orders - const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; - for (const order of orders) { - if (feeRecipientsToOrders[order.feeRecipientAddress] === undefined) { - feeRecipientsToOrders[order.feeRecipientAddress] = [] as SignedOrder[]; - } - feeRecipientsToOrders[order.feeRecipientAddress].push(order); - } - - const serverEndpointsToFeeRecipients: { [feeRecipient: string]: string[] } = {}; - for (const feeRecipient of Object.keys(feeRecipientsToOrders)) { - const endpoint = await this._getServerEndpointOrThrowAsync(feeRecipient); - if (serverEndpointsToFeeRecipients[endpoint] === undefined) { - serverEndpointsToFeeRecipients[endpoint] = []; - } - serverEndpointsToFeeRecipients[endpoint].push(feeRecipient); - } + const serverEndpointsToOrders = await this._mapServerEndpointsToOrdersAsync(orders); // make server requests let numErrors = 0; const errorResponses: CoordinatorServerResponse[] = []; const successResponses: CoordinatorServerCancellationResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); - for (const endpoint of Object.keys(serverEndpointsToFeeRecipients)) { + for (const endpoint of Object.keys(serverEndpointsToOrders)) { const response = await this._executeServerRequestAsync(transaction, makerAddress, endpoint); if (response.isError) { errorResponses.push(response); @@ -474,10 +458,7 @@ export class CoordinatorWrapper extends ContractWrapper { // lookup orders with errors const errorsWithOrders = errorResponses.map(resp => { const endpoint = resp.coordinatorOperator; - const feeRecipients: string[] = serverEndpointsToFeeRecipients[endpoint]; - const _orders = feeRecipients - .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) - .reduce(flatten, []); + const _orders = serverEndpointsToOrders[endpoint]; return { ...resp, orders: _orders, @@ -650,32 +631,14 @@ export class CoordinatorWrapper extends ContractWrapper { orderTransactionOpts: OrderTransactionOpts, ): Promise { const coordinatorOrders = signedOrders.filter(o => o.senderAddress === this.address); - - // create lookup tables to match server endpoints to orders - const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; - for (const order of coordinatorOrders) { - const feeRecipient = order.feeRecipientAddress; - if (feeRecipientsToOrders[feeRecipient] === undefined) { - feeRecipientsToOrders[feeRecipient] = [] as SignedOrder[]; - } - feeRecipientsToOrders[feeRecipient].push(order); - } - - const serverEndpointsToFeeRecipients: { [endpoint: string]: string[] } = {}; - for (const feeRecipient of Object.keys(feeRecipientsToOrders)) { - const endpoint = await this._getServerEndpointOrThrowAsync(feeRecipient); - if (serverEndpointsToFeeRecipients[endpoint] === undefined) { - serverEndpointsToFeeRecipients[endpoint] = []; - } - serverEndpointsToFeeRecipients[endpoint].push(feeRecipient); - } + const serverEndpointsToOrders = await this._mapServerEndpointsToOrdersAsync(coordinatorOrders); // make server requests let numErrors = 0; const errorResponses: CoordinatorServerResponse[] = []; const approvalResponses: CoordinatorServerResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, takerAddress); - for (const endpoint of Object.keys(serverEndpointsToFeeRecipients)) { + for (const endpoint of Object.keys(serverEndpointsToOrders)) { const response = await this._executeServerRequestAsync(transaction, takerAddress, endpoint); if (response.isError) { errorResponses.push(response); @@ -712,10 +675,7 @@ export class CoordinatorWrapper extends ContractWrapper { const approvedOrders = approvalResponses .map(resp => { const endpoint = resp.coordinatorOperator; - const feeRecipients = serverEndpointsToFeeRecipients[endpoint]; - const orders = feeRecipients - .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) - .reduce(flatten, []); + const orders = serverEndpointsToOrders[endpoint]; return orders; }) .reduce(flatten, []) @@ -724,10 +684,7 @@ export class CoordinatorWrapper extends ContractWrapper { // lookup orders with errors const errorsWithOrders = errorResponses.map(resp => { const endpoint = resp.coordinatorOperator; - const feeRecipients = serverEndpointsToFeeRecipients[endpoint]; - const orders = feeRecipients - .map(feeRecipient => feeRecipientsToOrders[feeRecipient]) - .reduce(flatten, []); + const orders = serverEndpointsToOrders[endpoint]; return { ...resp, orders, @@ -864,6 +821,28 @@ export class CoordinatorWrapper extends ContractWrapper { ); return txHash; } + + private async _mapServerEndpointsToOrdersAsync(coordinatorOrders: SignedOrder[]): Promise<{ [endpoint: string]: SignedOrder[] }> { + const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; + for (const order of coordinatorOrders) { + const feeRecipient = order.feeRecipientAddress; + if (feeRecipientsToOrders[feeRecipient] === undefined) { + feeRecipientsToOrders[feeRecipient] = [] as SignedOrder[]; + } + feeRecipientsToOrders[feeRecipient].push(order); + } + const serverEndpointsToOrders: { [endpoint: string]: SignedOrder[] } = {}; + for (const feeRecipient of Object.keys(feeRecipientsToOrders)) { + const endpoint = await this._getServerEndpointOrThrowAsync(feeRecipient); + const orders = feeRecipientsToOrders[feeRecipient]; + if (serverEndpointsToOrders[endpoint] === undefined) { + serverEndpointsToOrders[endpoint] = []; + } + serverEndpointsToOrders[endpoint] = serverEndpointsToOrders[endpoint].concat(orders); + } + return serverEndpointsToOrders; + } + } function getMakerAddressOrThrow(orders: Array): string { From e3916f58c4fade01090936be1124cb8fb43a5ffc Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 17:24:03 -0700 Subject: [PATCH 24/53] remove inline type declaration --- .../src/contract_wrappers/coordinator_wrapper.ts | 4 ++-- packages/contract-wrappers/src/types.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 2e379150d0..402e66e066 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -12,7 +12,7 @@ import * as _ from 'lodash'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; -import { OrderTransactionOpts } from '../types'; +import { CoordinatorTransaction, OrderTransactionOpts } from '../types'; import { assert } from '../utils/assert'; import { CoordinatorServerApprovalRawResponse, @@ -784,7 +784,7 @@ export class CoordinatorWrapper extends ContractWrapper { } private async _submitCoordinatorTransactionAsync( - transaction: { salt: BigNumber; signerAddress: string; data: string }, + transaction: CoordinatorTransaction, txOrigin: string, transactionSignature: string, approvalExpirationTimeSeconds: BigNumber[], diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index fba77af231..33e389866a 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -227,3 +227,5 @@ export interface DutchAuctionData { } export { CoordinatorServerCancellationResponse, CoordinatorServerError } from './utils/coordinator_server_types'; + +export interface CoordinatorTransaction { salt: BigNumber; signerAddress: string; data: string; } From f135aab7d4fd1894dfbb73ae320d1432c64d8443 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 17:28:08 -0700 Subject: [PATCH 25/53] dont swallow error when parsing json from http response --- .../src/contract_wrappers/coordinator_wrapper.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 402e66e066..59e4959bfd 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -763,13 +763,8 @@ export class CoordinatorWrapper extends ContractWrapper { }); const isError = response.status !== HttpStatus.OK; - - let json; - try { - json = await response.json(); - } catch (e) { - // ignore - } + const isValidationError = response.status === HttpStatus.BAD_REQUEST; + const json = isError && !isValidationError ? undefined : await response.json(); const result = { isError, From c386d2c0fbfd5a3a73c2d89e82db2947f082fab7 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 17:32:09 -0700 Subject: [PATCH 26/53] prettier --- .../src/contract_wrappers/coordinator_wrapper.ts | 9 +++++---- packages/contract-wrappers/src/types.ts | 8 ++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 59e4959bfd..ca0b964bc6 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -2,9 +2,9 @@ import { CoordinatorContract, CoordinatorRegistryContract, ExchangeContract } fr import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import { Coordinator, CoordinatorRegistry, Exchange } from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; -import { eip712Utils, generatePseudoRandomSalt, signatureUtils } from '@0x/order-utils'; +import { generatePseudoRandomSalt, signatureUtils } from '@0x/order-utils'; import { Order, SignedOrder, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; -import { BigNumber, fetchAsync, signTypedDataUtils } from '@0x/utils'; +import { BigNumber, fetchAsync } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { ContractAbi } from 'ethereum-types'; import * as HttpStatus from 'http-status-codes'; @@ -817,7 +817,9 @@ export class CoordinatorWrapper extends ContractWrapper { return txHash; } - private async _mapServerEndpointsToOrdersAsync(coordinatorOrders: SignedOrder[]): Promise<{ [endpoint: string]: SignedOrder[] }> { + private async _mapServerEndpointsToOrdersAsync( + coordinatorOrders: SignedOrder[], + ): Promise<{ [endpoint: string]: SignedOrder[] }> { const feeRecipientsToOrders: { [feeRecipient: string]: SignedOrder[] } = {}; for (const order of coordinatorOrders) { const feeRecipient = order.feeRecipientAddress; @@ -837,7 +839,6 @@ export class CoordinatorWrapper extends ContractWrapper { } return serverEndpointsToOrders; } - } function getMakerAddressOrThrow(orders: Array): string { diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 33e389866a..7ae38a5f08 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -9,7 +9,7 @@ import { WETH9Events, } from '@0x/abi-gen-wrappers'; import { ContractAddresses } from '@0x/contract-addresses'; -import { AssetData, Order, OrderState, SignedOrder, SignedZeroExTransaction } from '@0x/types'; +import { AssetData, OrderState, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { BlockParam, ContractEventArg, DecodedLogArgs, LogEntryEvent, LogWithDecodedArgs } from 'ethereum-types'; @@ -228,4 +228,8 @@ export interface DutchAuctionData { export { CoordinatorServerCancellationResponse, CoordinatorServerError } from './utils/coordinator_server_types'; -export interface CoordinatorTransaction { salt: BigNumber; signerAddress: string; data: string; } +export interface CoordinatorTransaction { + salt: BigNumber; + signerAddress: string; + data: string; +} From af2b1e6a5ce7f98f78a1df04fbd7e8b7fdee24f1 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 17:34:22 -0700 Subject: [PATCH 27/53] update Coordinator artifact --- .../artifacts/Coordinator.json | 256 +++++++++++++++--- 1 file changed, 216 insertions(+), 40 deletions(-) diff --git a/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json b/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json index 3c56715a8d..c8af051309 100644 --- a/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json +++ b/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json @@ -27,7 +27,7 @@ "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { "components": [ @@ -46,32 +46,58 @@ ], "name": "transaction", "type": "tuple" - }, - { - "name": "txOrigin", - "type": "address" - }, + } + ], + "name": "getTransactionHash", + "outputs": [ { - "name": "transactionSignature", - "type": "bytes" - }, + "name": "transactionHash", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ { - "name": "approvalExpirationTimeSeconds", - "type": "uint256[]" - }, + "components": [ + { + "name": "txOrigin", + "type": "address" + }, + { + "name": "transactionHash", + "type": "bytes32" + }, + { + "name": "transactionSignature", + "type": "bytes" + }, + { + "name": "approvalExpirationTimeSeconds", + "type": "uint256" + } + ], + "name": "approval", + "type": "tuple" + } + ], + "name": "getCoordinatorApprovalHash", + "outputs": [ { - "name": "approvalSignatures", - "type": "bytes[]" + "name": "approvalHash", + "type": "bytes32" } ], - "name": "executeTransaction", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "components": [ @@ -108,16 +134,16 @@ "type": "bytes[]" } ], - "name": "assertValidCoordinatorApprovals", + "name": "executeTransaction", "outputs": [], "payable": false, - "stateMutability": "view", + "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], - "name": "EIP712_DOMAIN_HASH", + "name": "EIP712_EXCHANGE_DOMAIN_HASH", "outputs": [ { "name": "", @@ -149,6 +175,39 @@ "name": "transaction", "type": "tuple" }, + { + "name": "txOrigin", + "type": "address" + }, + { + "name": "transactionSignature", + "type": "bytes" + }, + { + "name": "approvalExpirationTimeSeconds", + "type": "uint256[]" + }, + { + "name": "approvalSignatures", + "type": "bytes[]" + } + ], + "name": "assertValidCoordinatorApprovals", + "outputs": [], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "data", + "type": "bytes" + } + ], + "name": "decodeOrdersFromFillData", + "outputs": [ { "components": [ { @@ -202,26 +261,22 @@ ], "name": "orders", "type": "tuple[]" - }, - { - "name": "txOrigin", - "type": "address" - }, - { - "name": "transactionSignature", - "type": "bytes" - }, - { - "name": "approvalExpirationTimeSeconds", - "type": "uint256[]" - }, + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "EIP712_COORDINATOR_DOMAIN_HASH", + "outputs": [ { - "name": "approvalSignatures", - "type": "bytes[]" + "name": "", + "type": "bytes32" } ], - "name": "assertValidTransactionOrdersApproval", - "outputs": [], "payable": false, "stateMutability": "view", "type": "function" @@ -241,9 +296,130 @@ "evm": { "bytecode": { "linkReferences": {}, - "object": "0x60806040523480156200001157600080fd5b506040516020806200238083398101806040526200003391908101906200022b565b604080517f454950373132446f6d61696e28000000000000000000000000000000000000006020808301919091527f737472696e67206e616d652c0000000000000000000000000000000000000000602d8301527f737472696e672076657273696f6e2c000000000000000000000000000000000060398301527f6164647265737320766572696679696e67436f6e74726163740000000000000060488301527f29000000000000000000000000000000000000000000000000000000000000006061830152825180830360420181526062830180855281519183019190912060a28401855260179091527f30782050726f746f636f6c20436f6f7264696e61746f7200000000000000000060829093019290925282518084018452600581527f312e302e30000000000000000000000000000000000000000000000000000000908201528251808201929092527f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236828401527f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c6060830152306080808401919091528351808403909101815260a0909201909252805191012060005560018054600160a060020a031916600160a060020a039290921691909117905562000273565b600062000224825162000260565b9392505050565b6000602082840312156200023e57600080fd5b60006200024c848462000216565b949350505050565b600160a060020a031690565b60006200026d8262000254565b92915050565b6120fd80620002836000396000f3fe608060405234801561001057600080fd5b5060043610610084576000357c010000000000000000000000000000000000000000000000000000000090048063d2df07331161006d578063d2df0733146100c7578063e306f779146100da578063e3b1aa86146100ef57610084565b80630f7d8e391461008957806390c3bc3f146100b2575b600080fd5b61009c610097366004611888565b610102565b6040516100a99190611e6f565b60405180910390f35b6100c56100c036600461196e565b6104f7565b005b6100c56100d536600461196e565b6105a3565b6100e26105d4565b6040516100a99190611e7d565b6100c56100fd366004611a42565b6105da565b6000808251111515610149576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f3b565b60405180910390fd5b600061015483610821565b7f010000000000000000000000000000000000000000000000000000000000000090049050600360ff8216106101b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611efb565b60008160ff1660038111156101c757fe5b905060008160038111156101d757fe5b141561020f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f2b565b600181600381111561021d57fe5b141561035b57835160411461025e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611e8b565b600084600081518110151561026f57fe5b01602001517f010000000000000000000000000000000000000000000000000000000000000090819004810204905060006102b186600163ffffffff6108e516565b905060006102c687602163ffffffff6108e516565b905060018884848460405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610325573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104f195505050505050565b600281600381111561036957fe5b14156104bf5783516041146103aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611e8b565b60008460008151811015156103bb57fe5b01602001517f010000000000000000000000000000000000000000000000000000000000000090819004810204905060006103fd86600163ffffffff6108e516565b9050600061041287602163ffffffff6108e516565b905060018860405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c018281526020019150506040516020818303038152906040528051906020012084848460405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610325573d6000803e3d6000fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611efb565b92915050565b61050485858585856105a3565b6001548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056a93909290918990600401611f5b565b600060405180830381600087803b15801561058457600080fd5b505af1158015610598573d6000803e3d6000fd5b505050505050505050565b60606105b28660400151610930565b90506000815111156105cc576105cc8682878787876105da565b505050505050565b60005481565b3273ffffffffffffffffffffffffffffffffffffffff851614610629576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f0b565b600061063487610de8565b60408051600080825260208201909252845192935091905b80821461073c576000868281518110151561066357fe5b906020019060200201519050610677611220565b506040805160808101825273ffffffffffffffffffffffffffffffffffffffff8b16815260208101879052908101899052606081018290524282116106e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611edb565b60006106f382610dfb565b90506000610718828a8781518110151561070957fe5b90602001906020020151610102565b905061072a878263ffffffff610e0916565b9650506001909301925061064c915050565b5061074d823263ffffffff610e0916565b885190925060005b8082146108145789516000908b908390811061076d57fe5b906020019060200201516060015173ffffffffffffffffffffffffffffffffffffffff16141561079c5761080c565b60008a828151811015156107ac57fe5b6020908102909101015160400151905060006107ce868363ffffffff610ed316565b9050801515610809576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611e9b565b50505b600101610755565b5050505050505050505050565b600080825111151561085f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f1b565b815182907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811061088f57fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01909252507f0100000000000000000000000000000000000000000000000000000000000000908190040290565b600081602001835110151515610927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611eeb565b50016020015190565b60606000610944838263ffffffff610f1016565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d50000000000000000000000000000000000000000000000000000000014806109d757507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b80610a2357507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610aad57610a30611248565b8351610a4690859060049063ffffffff610f7d16565b806020019051610a5991908101906118da565b604080516001808252818301909252919250816020015b610a78611248565b815260200190600190039081610a7057905050925080836000815181101515610a9d57fe5b6020908102909101015250610de2565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b000000000000000000000000000000000000000000000000000000001480610b3e57507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b80610b8a57507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b80610bd657507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b80610c2257507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b80610c6e57507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b80610cba57507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b15610cef578251610cd590849060049063ffffffff610f7d16565b806020019051610ce8919081019061184b565b9150610de2565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610de257610d41611248565b610d49611248565b8451610d5f90869060049063ffffffff610f7d16565b806020019051610d72919081019061190f565b60408051600280825260608201909252929450909250816020015b610d95611248565b815260200190600190039081610d8d57905050935081846000815181101515610dba57fe5b602090810290910101528351819085906001908110610dd557fe5b6020908102909101015250505b50919050565b60006104f1610df683611049565b6110b7565b60006104f1610df6836110f7565b815160405160609184906020808202808401820192910182851015610e5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611ecb565b82851115610e7457610e6d858583611156565b8497508793505b600182019150602081019050808401925082945081885284604052868860018403815181101515610ea157fe5b73ffffffffffffffffffffffffffffffffffffffff909216602092830290910190910152508694505050505092915050565b6000602083510260208401818101815b81811015610f0657805180871415610efd57600195508291505b50602001610ee3565b5050505092915050565b600081600401835110151515610f52576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611f4b565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610fb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611eab565b8351821115610ff4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014090611ebb565b8282036040519080825280601f01601f191660200182016040528015611021576020820181803883390190505b5090506110426110308261121a565b8461103a8761121a565b018351611156565b9392505050565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b6000546040517f19010000000000000000000000000000000000000000000000000000000000008152600281019190915260228101919091526042902090565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b6020811015611180576001816020036101000a038019835116818551168082178652505050611215565b8282141561118d57611215565b828211156111c75760208103905080820181840181515b828510156111bf5784518652602095860195909401936111a4565b905250611215565b60208103905080820181840183515b8186121561121057825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe092830192909101906111d6565b855250505b505050565b60200190565b6040805160808101825260008082526020820181905260609282018390529181019190915290565b61018060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b60006110428235612038565b60006110428251612038565b6000601f8201831361132b57600080fd5b813561133e61133982611fcd565b611fa6565b81815260209384019390925082018360005b83811015610f06578135860161136688826114b2565b8452506020928301929190910190600101611350565b6000601f8201831361138d57600080fd5b815161139b61133982611fcd565b81815260209384019390925082018360005b83811015610f0657815186016113c38882611690565b84525060209283019291909101906001016113ad565b6000601f820183136113ea57600080fd5b81356113f861133982611fcd565b81815260209384019390925082018360005b83811015610f0657813586016114208882611547565b845250602092830192919091019060010161140a565b6000601f8201831361144757600080fd5b813561145561133982611fcd565b9150818183526020840193506020810190508385602084028201111561147a57600080fd5b60005b83811015610f06578161149088826114a6565b845250602092830192919091019060010161147d565b60006110428235612043565b6000601f820183136114c357600080fd5b81356114d161133982611fee565b915080825260208301602083018583830111156114ed57600080fd5b6114f883828461205f565b50505092915050565b6000601f8201831361151257600080fd5b815161152061133982611fee565b9150808252602083016020830185838301111561153c57600080fd5b6114f883828461206b565b6000610180828403121561155a57600080fd5b611565610180611fa6565b905060006115738484611302565b825250602061158484848301611302565b602083015250604061159884828501611302565b60408301525060606115ac84828501611302565b60608301525060806115c0848285016114a6565b60808301525060a06115d4848285016114a6565b60a08301525060c06115e8848285016114a6565b60c08301525060e06115fc848285016114a6565b60e083015250610100611611848285016114a6565b61010083015250610120611627848285016114a6565b6101208301525061014082013567ffffffffffffffff81111561164957600080fd5b611655848285016114b2565b6101408301525061016082013567ffffffffffffffff81111561167757600080fd5b611683848285016114b2565b6101608301525092915050565b600061018082840312156116a357600080fd5b6116ae610180611fa6565b905060006116bc848461130e565b82525060206116cd8484830161130e565b60208301525060406116e18482850161130e565b60408301525060606116f58482850161130e565b60608301525060806117098482850161183f565b60808301525060a061171d8482850161183f565b60a08301525060c06117318482850161183f565b60c08301525060e06117458482850161183f565b60e08301525061010061175a8482850161183f565b610100830152506101206117708482850161183f565b6101208301525061014082015167ffffffffffffffff81111561179257600080fd5b61179e84828501611501565b6101408301525061016082015167ffffffffffffffff8111156117c057600080fd5b61168384828501611501565b6000606082840312156117de57600080fd5b6117e86060611fa6565b905060006117f684846114a6565b825250602061180784848301611302565b602083015250604082013567ffffffffffffffff81111561182757600080fd5b611833848285016114b2565b60408301525092915050565b60006110428251612043565b60006020828403121561185d57600080fd5b815167ffffffffffffffff81111561187457600080fd5b6118808482850161137c565b949350505050565b6000806040838503121561189b57600080fd5b60006118a785856114a6565b925050602083013567ffffffffffffffff8111156118c457600080fd5b6118d0858286016114b2565b9150509250929050565b6000602082840312156118ec57600080fd5b815167ffffffffffffffff81111561190357600080fd5b61188084828501611690565b6000806040838503121561192257600080fd5b825167ffffffffffffffff81111561193957600080fd5b61194585828601611690565b925050602083015167ffffffffffffffff81111561196257600080fd5b6118d085828601611690565b600080600080600060a0868803121561198657600080fd5b853567ffffffffffffffff81111561199d57600080fd5b6119a9888289016117cc565b95505060206119ba88828901611302565b945050604086013567ffffffffffffffff8111156119d757600080fd5b6119e3888289016114b2565b935050606086013567ffffffffffffffff811115611a0057600080fd5b611a0c88828901611436565b925050608086013567ffffffffffffffff811115611a2957600080fd5b611a358882890161131a565b9150509295509295909350565b60008060008060008060c08789031215611a5b57600080fd5b863567ffffffffffffffff811115611a7257600080fd5b611a7e89828a016117cc565b965050602087013567ffffffffffffffff811115611a9b57600080fd5b611aa789828a016113d9565b9550506040611ab889828a01611302565b945050606087013567ffffffffffffffff811115611ad557600080fd5b611ae189828a016114b2565b935050608087013567ffffffffffffffff811115611afe57600080fd5b611b0a89828a01611436565b92505060a087013567ffffffffffffffff811115611b2757600080fd5b611b3389828a0161131a565b9150509295509295509295565b611b4981612038565b82525050565b611b4981612043565b6000611b6382612034565b808452611b7781602086016020860161206b565b611b808161209b565b9093016020019392505050565b601281527f4c454e4754485f36355f52455155495245440000000000000000000000000000602082015260400190565b601a81527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000602082015260400190565b601a81527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000602082015260400190565b601c81527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000602082015260400190565b601781527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000602082015260400190565b601081527f415050524f56414c5f4558504952454400000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601581527f5349474e41545552455f554e535550504f525445440000000000000000000000602082015260400190565b600e81527f494e56414c49445f4f524947494e000000000000000000000000000000000000602082015260400190565b602181527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560208201527f4400000000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f5349474e41545552455f494c4c4547414c000000000000000000000000000000602082015260400190565b601e81527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000602082015260400190565b602581527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160208201527f5549524544000000000000000000000000000000000000000000000000000000604082015260600190565b602081016104f18284611b40565b602081016104f18284611b4f565b602080825281016104f181611b8d565b602080825281016104f181611bbd565b602080825281016104f181611bed565b602080825281016104f181611c1d565b602080825281016104f181611c4d565b602080825281016104f181611c7d565b602080825281016104f181611cad565b602080825281016104f181611d03565b602080825281016104f181611d33565b602080825281016104f181611d63565b602080825281016104f181611db9565b602080825281016104f181611de9565b602080825281016104f181611e19565b60808101611f698287611b4f565b611f766020830186611b40565b8181036040830152611f888185611b58565b90508181036060830152611f9c8184611b58565b9695505050505050565b60405181810167ffffffffffffffff81118282101715611fc557600080fd5b604052919050565b600067ffffffffffffffff821115611fe457600080fd5b5060209081020190565b600067ffffffffffffffff82111561200557600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b5190565b60006104f182612046565b90565b73ffffffffffffffffffffffffffffffffffffffff1690565b82818337506000910152565b60005b8381101561208657818101518382015260200161206e565b83811115612095576000848401525b50505050565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169056fea265627a7a7230582013be4e9e281ff59b6be3d1c4c7af6075c7d255edc60be429d25841f98f287b3e6c6578706572696d656e74616cf50037" + "object": "0x60806040523480156200001157600080fd5b506040516020806200235b833981018060405262000033919081019062000252565b600080546001600160a01b0319166001600160a01b0383161790556040516200005f906020016200029f565b60408051601f1981840301815282825280516020918201208383018352601784527f30782050726f746f636f6c20436f6f7264696e61746f720000000000000000009382019390935281518083018352600581527f312e302e300000000000000000000000000000000000000000000000000000009082015290516200012d92917f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236917f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9130910162000284565b60408051601f198184030181529082905280516020918201206001556200015591016200029f565b60408051601f1981840301815282825280516020918201208383018352600b84527f30782050726f746f636f6c0000000000000000000000000000000000000000009382019390935281518083018352600181527f32000000000000000000000000000000000000000000000000000000000000009082015260005491516200023093927ff0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61e927fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5926001600160a01b03909216910162000284565b60408051601f1981840301815291905280516020909101206002555062000360565b6000602082840312156200026557600080fd5b81516001600160a01b03811681146200027d57600080fd5b9392505050565b93845260208401929092526040830152606082015260800190565b7f454950373132446f6d61696e280000000000000000000000000000000000000081527f737472696e67206e616d652c0000000000000000000000000000000000000000600d8201527f737472696e672076657273696f6e2c000000000000000000000000000000000060198201527f6164647265737320766572696679696e67436f6e74726163740000000000000060288201527f2900000000000000000000000000000000000000000000000000000000000000604182015260420190565b611feb80620003706000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH3 0x11 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH3 0x235B DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE PUSH3 0x33 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH3 0x252 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND OR SWAP1 SSTORE PUSH1 0x40 MLOAD PUSH3 0x5F SWAP1 PUSH1 0x20 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0x17 DUP5 MSTORE PUSH32 0x30782050726F746F636F6C20436F6F7264696E61746F72000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x5 DUP2 MSTORE PUSH32 0x312E302E30000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE SWAP1 MLOAD PUSH3 0x12D SWAP3 SWAP2 PUSH32 0x626D101E477FD17DD52AFB3F9AD9EB016BF60F6E377877F34E8F3EA84C930236 SWAP2 PUSH32 0x6C015BD22B4C69690933C1058878EBDFEF31F9AAAE40BBE86D8A09FE1B2972C SWAP2 ADDRESS SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 PUSH1 0x1 SSTORE PUSH3 0x155 SWAP2 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0xB DUP5 MSTORE PUSH32 0x30782050726F746F636F6C000000000000000000000000000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x1 DUP2 MSTORE PUSH32 0x3200000000000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE PUSH1 0x0 SLOAD SWAP2 MLOAD PUSH3 0x230 SWAP4 SWAP3 PUSH32 0xF0F24618F4C4BE1E62E026FB039A20EF96F4495294817D1027FFAA6D1F70E61E SWAP3 PUSH32 0xAD7C5BEF027816A800DA1736444FB58A807EF4C9603B7848673F7E3A68EB14A5 SWAP3 PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP2 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP1 SWAP2 ADD KECCAK256 PUSH1 0x2 SSTORE POP PUSH3 0x360 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH3 0x265 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH3 0x27D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0x20 DUP5 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH32 0x454950373132446F6D61696E2800000000000000000000000000000000000000 DUP2 MSTORE PUSH32 0x737472696E67206E616D652C0000000000000000000000000000000000000000 PUSH1 0xD DUP3 ADD MSTORE PUSH32 0x737472696E672076657273696F6E2C0000000000000000000000000000000000 PUSH1 0x19 DUP3 ADD MSTORE PUSH32 0x6164647265737320766572696679696E67436F6E747261637400000000000000 PUSH1 0x28 DUP3 ADD MSTORE PUSH32 0x2900000000000000000000000000000000000000000000000000000000000000 PUSH1 0x41 DUP3 ADD MSTORE PUSH1 0x42 ADD SWAP1 JUMP JUMPDEST PUSH2 0x1FEB DUP1 PUSH3 0x370 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC26CFECD GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xC26CFECD EQ PUSH2 0xFE JUMPI DUP1 PUSH4 0xD2DF0733 EQ PUSH2 0x106 JUMPI DUP1 PUSH4 0xEE55B968 EQ PUSH2 0x119 JUMPI DUP1 PUSH4 0xFB6961CC EQ PUSH2 0x139 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0xF7D8E39 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x23872F55 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0x48A321D6 EQ PUSH2 0xD6 JUMPI DUP1 PUSH4 0x90C3BC3F EQ PUSH2 0xE9 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA0 PUSH2 0x9B CALLDATASIZE PUSH1 0x4 PUSH2 0x15D7 JUMP JUMPDEST PUSH2 0x141 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1958 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xC9 PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x177C JUMP JUMPDEST PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1AAD JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xE4 CALLDATASIZE PUSH1 0x4 PUSH2 0x165B JUMP JUMPDEST PUSH2 0x4E7 JUMP JUMPDEST PUSH2 0xFC PUSH2 0xF7 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x4FA JUMP JUMPDEST STOP JUMPDEST PUSH2 0xC9 PUSH2 0x5A6 JUMP JUMPDEST PUSH2 0xFC PUSH2 0x114 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x5AC JUMP JUMPDEST PUSH2 0x12C PUSH2 0x127 CALLDATASIZE PUSH1 0x4 PUSH2 0x161E JUMP JUMPDEST PUSH2 0x5DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1979 JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xA8F JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0x186 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D7D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x191 DUP4 PUSH2 0xA95 JUMP JUMPDEST PUSH1 0xF8 SHR SWAP1 POP PUSH1 0x4 DUP2 LT PUSH2 0x1D0 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0xFF AND PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1E1 JUMPI INVALID JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1F1 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x229 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D46 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x237 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x2A8 JUMPI DUP4 MLOAD ISZERO PUSH2 0x276 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1E48 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DB4 JUMP JUMPDEST PUSH1 0x2 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x2B6 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x3BB JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x2F7 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x306 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x329 DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x33E DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x385 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP7 POP PUSH2 0x4CE SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x3 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x3C9 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x49C JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x40A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x419 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x43C DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x451 DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x466 SWAP2 SWAP1 PUSH2 0x1927 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4E2 DUP4 PUSH2 0xB61 JUMP JUMPDEST PUSH2 0xBCF JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4F5 DUP4 PUSH2 0xBDD JUMP JUMPDEST PUSH2 0xC3C JUMP JUMPDEST PUSH2 0x507 DUP6 DUP6 DUP6 DUP6 DUP6 PUSH2 0x5AC JUMP JUMPDEST PUSH1 0x0 SLOAD DUP6 MLOAD PUSH1 0x20 DUP8 ADD MLOAD PUSH1 0x40 DUP1 DUP10 ADD MLOAD SWAP1 MLOAD PUSH32 0xBFC8BFCE00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP5 AND SWAP4 PUSH4 0xBFC8BFCE SWAP4 PUSH2 0x56D SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP10 SWAP1 PUSH1 0x4 ADD PUSH2 0x1E7F JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x587 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x59B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x60 PUSH2 0x5BB DUP7 PUSH1 0x40 ADD MLOAD PUSH2 0x5DB JUMP JUMPDEST DUP1 MLOAD SWAP1 SWAP2 POP ISZERO PUSH2 0x5D3 JUMPI PUSH2 0x5D3 DUP7 DUP3 DUP8 DUP8 DUP8 DUP8 PUSH2 0xC4A JUMP JUMPDEST POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x0 PUSH2 0x5EF DUP4 DUP3 PUSH4 0xFFFFFFFF PUSH2 0xE98 AND JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xB4BE83D500000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x682 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3E228BAE00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x6CE JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x64A3BC1500000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x757 JUMPI PUSH2 0x6DB PUSH2 0x11DB JUMP JUMPDEST DUP4 MLOAD PUSH2 0x6F1 SWAP1 DUP6 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x704 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x16ED JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 DUP1 DUP3 MSTORE DUP2 DUP4 ADD SWAP1 SWAP3 MSTORE SWAP2 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0x723 PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x71B JUMPI SWAP1 POP POP SWAP3 POP DUP1 DUP4 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x746 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x297BB70B00000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x7E8 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x50DDE19000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x834 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x4D0AE54600000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x880 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xE5FA431B00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x8CC JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xA3E2038000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x918 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x7E1D980800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x964 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xDD1C7D1800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x999 JUMPI DUP3 MLOAD PUSH2 0x97F SWAP1 DUP5 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x992 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x154B JUMP JUMPDEST SWAP2 POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 EQ ISZERO PUSH2 0xA89 JUMPI PUSH2 0x9EB PUSH2 0x11DB JUMP JUMPDEST PUSH2 0x9F3 PUSH2 0x11DB JUMP JUMPDEST DUP5 MLOAD PUSH2 0xA09 SWAP1 DUP7 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0xA1C SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x1722 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 ADD SWAP1 SWAP3 MSTORE SWAP3 SWAP5 POP SWAP1 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0xA3F PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0xA37 JUMPI SWAP1 POP POP SWAP4 POP DUP2 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0xA62 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP DUP1 DUP5 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0xA7B JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP POP JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x1 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0xAD1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CE9 JUMP JUMPDEST DUP2 PUSH1 0x1 DUP4 MLOAD SUB DUP2 MLOAD DUP2 LT PUSH2 0xAE1 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD DUP3 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ADD SWAP1 SWAP3 MSTORE POP PUSH1 0xF8 SWAP1 DUP2 SHR SWAP1 SHL SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO PUSH2 0xB58 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C1E JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP2 DUP2 ADD MLOAD DUP3 MLOAD PUSH1 0x20 SWAP4 DUP5 ADD MLOAD DUP3 MLOAD SWAP3 DUP6 ADD SWAP3 SWAP1 SWAP3 KECCAK256 DUP4 MLOAD PUSH32 0x213C6F636F3EA94E701C0ADF9B2624AA45A6C694F9A292C094F9A81C24B5DF4C DUP2 MSTORE SWAP5 DUP6 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x2 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST PUSH1 0x40 DUP1 DUP3 ADD MLOAD DUP3 MLOAD PUSH1 0x20 DUP1 DUP6 ADD MLOAD PUSH1 0x60 DUP7 DUP2 ADD MLOAD DUP6 MLOAD SWAP6 DUP5 ADD SWAP6 SWAP1 SWAP6 KECCAK256 DUP7 MLOAD PUSH32 0x2FBCDBAA76BC7589916958AE919DFBEF04D23F6BBF26DE6FF317B32C6CC01E05 DUP2 MSTORE SWAP4 DUP5 ADD SWAP5 SWAP1 SWAP5 MSTORE SWAP5 DUP3 ADD MSTORE SWAP3 DUP4 ADD MSTORE PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 SWAP1 KECCAK256 SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x1 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST ORIGIN PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND EQ PUSH2 0xC99 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CB2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xCA4 DUP8 PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 SWAP3 MSTORE DUP5 MLOAD SWAP3 SWAP4 POP SWAP2 SWAP1 JUMPDEST DUP2 DUP2 EQ PUSH2 0xDA5 JUMPI PUSH1 0x0 DUP7 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xCD1 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD SWAP1 POP PUSH2 0xCE3 PUSH2 0x1294 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP11 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 MSTORE POP SWAP1 POP TIMESTAMP DUP3 GT PUSH2 0xD55 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BE7 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xD60 DUP3 PUSH2 0x4E7 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xD81 DUP3 DUP11 DUP8 DUP2 MLOAD DUP2 LT PUSH2 0xD74 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH2 0x141 JUMP JUMPDEST SWAP1 POP PUSH2 0xD93 DUP8 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST SWAP7 POP POP PUSH1 0x1 SWAP1 SWAP4 ADD SWAP3 POP PUSH2 0xCBC SWAP2 POP POP JUMP JUMPDEST POP PUSH2 0xDB6 DUP3 ORIGIN PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST DUP9 MLOAD SWAP1 SWAP3 POP PUSH1 0x0 JUMPDEST DUP2 DUP2 EQ PUSH2 0xE8B JUMPI PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xDE9 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x60 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xE16 JUMPI PUSH2 0xE83 JUMP JUMPDEST PUSH1 0x0 DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xE24 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x40 ADD MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0xE47 DUP3 DUP8 PUSH2 0x10D0 SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST SWAP1 POP DUP1 PUSH2 0xE80 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B0B JUMP JUMPDEST POP POP JUMPDEST PUSH1 0x1 ADD PUSH2 0xDBE JUMP JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x4 ADD DUP4 MLOAD LT ISZERO PUSH2 0xED8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DEB JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 AND SWAP1 JUMP JUMPDEST PUSH1 0x60 DUP2 DUP4 GT ISZERO PUSH2 0xF3F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B42 JUMP JUMPDEST DUP4 MLOAD DUP3 GT ISZERO PUSH2 0xF7A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B79 JUMP JUMPDEST DUP3 DUP3 SUB PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0xFA7 JUMPI PUSH1 0x20 DUP3 ADD DUP2 DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH2 0xFC8 PUSH2 0xFB6 DUP3 PUSH2 0x1111 JUMP JUMPDEST DUP5 PUSH2 0xFC0 DUP8 PUSH2 0x1111 JUMP JUMPDEST ADD DUP4 MLOAD PUSH2 0x1117 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x2 DUP2 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x22 DUP3 ADD MSTORE PUSH1 0x42 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST DUP2 MLOAD PUSH1 0x40 MLOAD PUSH1 0x60 SWAP2 DUP5 SWAP1 PUSH1 0x20 DUP1 DUP3 MUL DUP1 DUP5 ADD DUP3 ADD SWAP3 SWAP2 ADD DUP3 DUP6 LT ISZERO PUSH2 0x105A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BB0 JUMP JUMPDEST DUP3 DUP6 GT ISZERO PUSH2 0x1074 JUMPI PUSH2 0x106D DUP6 DUP6 DUP4 PUSH2 0x1117 JUMP JUMPDEST DUP5 SWAP8 POP DUP8 SWAP4 POP JUMPDEST PUSH1 0x1 DUP3 ADD SWAP2 POP PUSH1 0x20 DUP2 ADD SWAP1 POP DUP1 DUP5 ADD SWAP3 POP DUP3 SWAP5 POP DUP2 DUP9 MSTORE DUP5 PUSH1 0x40 MSTORE DUP7 DUP9 PUSH1 0x1 DUP5 SUB DUP2 MLOAD DUP2 LT PUSH2 0x109F JUMPI INVALID JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND PUSH1 0x20 SWAP3 DUP4 MUL SWAP2 SWAP1 SWAP2 ADD SWAP1 SWAP2 ADD MSTORE POP SWAP6 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP4 MLOAD MUL PUSH1 0x20 DUP5 ADD DUP2 DUP2 ADD DUP2 SWAP3 POP JUMPDEST DUP1 DUP4 LT ISZERO PUSH2 0x1108 JUMPI DUP3 MLOAD DUP1 DUP7 EQ ISZERO PUSH2 0x10FC JUMPI PUSH1 0x1 SWAP5 POP DUP2 SWAP4 POP JUMPDEST POP PUSH1 0x20 DUP4 ADD SWAP3 POP PUSH2 0x10E2 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1141 JUMPI PUSH1 0x1 DUP2 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP4 MLOAD AND DUP2 DUP6 MLOAD AND DUP1 DUP3 OR DUP7 MSTORE POP POP POP PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 EQ ISZERO PUSH2 0x114E JUMPI PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 GT ISZERO PUSH2 0x1188 JUMPI PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP2 MLOAD JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x1180 JUMPI DUP5 MLOAD DUP7 MSTORE PUSH1 0x20 SWAP6 DUP7 ADD SWAP6 SWAP1 SWAP5 ADD SWAP4 PUSH2 0x1165 JUMP JUMPDEST SWAP1 MSTORE POP PUSH2 0x11D6 JUMP JUMPDEST PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP4 MLOAD JUMPDEST DUP2 DUP7 SLT ISZERO PUSH2 0x11D1 JUMPI DUP3 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP3 DUP4 ADD SWAP3 SWAP1 SWAP2 ADD SWAP1 PUSH2 0x1197 JUMP JUMPDEST DUP6 MSTORE POP POP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH2 0x180 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP1 NOT AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x4CE DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x12F0 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1303 PUSH2 0x12FE DUP3 PUSH2 0x1EF8 JUMP JUMPDEST PUSH2 0x1ED1 JUMP JUMPDEST DUP2 DUP2 MSTORE SWAP2 POP PUSH1 0x20 DUP1 DUP4 ADD SWAP1 DUP5 ADD PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1340 JUMPI PUSH2 0x132B DUP8 PUSH1 0x20 DUP5 CALLDATALOAD DUP10 ADD ADD PUSH2 0x134A JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 SWAP3 DUP4 ADD SWAP3 SWAP2 SWAP1 SWAP2 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1313 JUMP JUMPDEST POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x135A JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1368 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x137F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x13A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH2 0x13B7 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x13CE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x13DF DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x13F9 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x1402 DUP2 PUSH2 0x1ED1 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x140F DUP4 DUP4 PUSH2 0x12D5 JUMP JUMPDEST DUP2 MSTORE PUSH2 0x141E DUP4 PUSH1 0x20 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH2 0x1430 DUP4 PUSH1 0x40 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD MSTORE PUSH2 0x1442 DUP4 PUSH1 0x60 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP3 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP3 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP3 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x14A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x14B0 DUP7 DUP4 DUP8 ADD PUSH2 0x1398 JUMP JUMPDEST DUP4 DUP6 ADD MSTORE PUSH2 0x160 SWAP3 POP DUP3 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x14CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x14D9 DUP6 DUP3 DUP7 ADD PUSH2 0x1398 JUMP JUMPDEST DUP3 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x14F6 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x1500 PUSH1 0x60 PUSH2 0x1ED1 JUMP JUMPDEST SWAP1 POP DUP2 CALLDATALOAD DUP2 MSTORE PUSH1 0x20 DUP3 ADD CALLDATALOAD PUSH2 0x1514 DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1533 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x153F DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x155D JUMPI DUP2 DUP3 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1573 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP1 DUP5 ADD DUP6 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1584 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 MLOAD SWAP2 POP PUSH2 0x1594 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP4 DUP2 ADD SWAP1 DUP3 DUP6 ADD DUP7 JUMPDEST DUP6 DUP2 LT ISZERO PUSH2 0x15C9 JUMPI PUSH2 0x15B7 DUP11 DUP9 DUP5 MLOAD DUP9 ADD ADD PUSH2 0x13E6 JUMP JUMPDEST DUP5 MSTORE SWAP3 DUP7 ADD SWAP3 SWAP1 DUP7 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x15A0 JUMP JUMPDEST POP SWAP1 SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x15EA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 CALLDATALOAD SWAP2 POP PUSH1 0x20 DUP4 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1608 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x134A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x1630 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1647 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x166C JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x1683 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x80 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x1695 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x169F PUSH1 0x80 PUSH2 0x1ED1 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD PUSH2 0x16AC DUP2 PUSH2 0x1F8C JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 DUP2 DUP2 ADD CALLDATALOAD SWAP1 DUP5 ADD MSTORE PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x16C9 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x16D5 DUP8 DUP3 DUP5 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP PUSH1 0x60 SWAP1 DUP2 ADD CALLDATALOAD SWAP1 DUP4 ADD MSTORE POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x16FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1716 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x1735 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x174D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1759 DUP7 DUP4 DUP8 ADD PUSH2 0x13E6 JUMP JUMPDEST SWAP4 POP PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x176F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x178E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x17A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x14E5 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x17C8 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x17DF JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x17EB DUP10 DUP4 DUP11 ADD PUSH2 0x14E5 JUMP JUMPDEST SWAP7 POP PUSH1 0x20 SWAP2 POP DUP2 DUP9 ADD CALLDATALOAD PUSH2 0x17FE DUP2 PUSH2 0x1F8C JUMP JUMPDEST SWAP6 POP PUSH1 0x40 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1811 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x181D DUP11 DUP3 DUP12 ADD PUSH2 0x134A JUMP JUMPDEST SWAP6 POP POP PUSH1 0x60 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1831 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 DUP10 ADD DUP11 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1842 JUMPI DUP5 DUP6 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP2 POP PUSH2 0x1852 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP5 DUP2 ADD SWAP1 DUP3 DUP7 ADD DUP7 DUP6 MUL DUP5 ADD DUP8 ADD DUP15 LT ISZERO PUSH2 0x186E JUMPI DUP8 DUP9 REVERT JUMPDEST DUP8 SWAP4 POP JUMPDEST DUP5 DUP5 LT ISZERO PUSH2 0x1890 JUMPI DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x1 SWAP4 SWAP1 SWAP4 ADD SWAP3 SWAP2 DUP7 ADD SWAP2 DUP7 ADD PUSH2 0x1872 JUMP JUMPDEST POP SWAP7 POP POP POP POP PUSH1 0x80 DUP9 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x18A9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x18B6 DUP9 DUP3 DUP10 ADD PUSH2 0x12E0 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 POP SWAP3 SWAP6 SWAP1 SWAP4 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 MSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x18F5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE PUSH1 0x1C DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x3C ADD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x1AA0 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE DUP2 MLOAD PUSH2 0x180 PUSH2 0x19DE DUP8 DUP4 MLOAD PUSH2 0x18C3 JUMP JUMPDEST DUP8 DUP3 ADD MLOAD PUSH2 0x19EE DUP10 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0x1A01 PUSH1 0x40 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0x1A14 PUSH1 0x60 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP9 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP9 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP9 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP9 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD DUP3 DUP3 DUP11 ADD MSTORE PUSH2 0x1A6D DUP4 DUP11 ADD DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 SWAP2 POP DUP2 DUP4 ADD MLOAD DUP9 DUP3 SUB DUP4 DUP11 ADD MSTORE PUSH2 0x1A8A DUP3 DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP9 POP POP POP SWAP5 DUP8 ADD SWAP5 POP POP SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x199F JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x12 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F36355F52455155495245440000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F415050524F56414C5F5349474E4154555245000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x46524F4D5F4C4553535F5448414E5F544F5F5245515549524544000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1C SWAP1 DUP3 ADD MSTORE PUSH32 0x544F5F4C4553535F5448414E5F4C454E4754485F524551554952454400000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x17 SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F465245455F4D454D4F52595F505452000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x10 SWAP1 DUP3 ADD MSTORE PUSH32 0x415050524F56414C5F4558504952454400000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x26 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x15 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F554E535550504F525445440000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F4F524947494E000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x21 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F5448414E5F5A45524F5F4C454E4754485F52455155495245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x4400000000000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494C4C4547414C000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1E SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F475245415445525F5448414E5F305F52455155495245440000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494E56414C4944000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x25 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F345F4C454E4754485F524551 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5549524544000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F305F5245515549524544000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP6 DUP3 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH1 0x80 PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1EB4 PUSH1 0x80 DUP4 ADD DUP6 PUSH2 0x18DD JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x60 DUP5 ADD MSTORE PUSH2 0x1EC6 DUP2 DUP6 PUSH2 0x18DD JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1EF0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F0F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 SWAP1 DUP2 MUL ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F30 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1F77 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1F5F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1F86 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x1FAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xbc 0xdb 0x4a 0xab RETURNDATACOPY BYTE DIV 0xea 0x5c 0xd6 0xc1 CODESIZE SWAP2 GT AND 0xce 0xac EXTCODEHASH 0xac DUP9 0xde NOT SWAP6 0xc4 0xd3 CALLCODE 0x4f 0xdd EXTCODEHASH TIMESTAMP 0xf 0xb6 PUSH13 0x6578706572696D656E74616CF5 STOP CALLDATACOPY ", + "sourceMap": "838:227:0:-;;;978:85;8:9:-1;5:2;;;30:1;27;20:12;5:2;978:85:0;;;;;;;;;;;;;;;;;;;;;;830:8:8;:35;;-1:-1:-1;;;;;;830:35:8;-1:-1:-1;;;;;830:35:8;;;;;1425:148:10;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2101:30;;;;;;;;;;;;;;;;2163:33;;;;;;;;;;;;;;;2006:238;;;;1415:159;2085:48;;2147:51;;2228:4;;2006:238;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2006:238:10;;;;1996:249;;49:4:-1;1996:249:10;;;;1963:30;:282;1425:148;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2391:27;;;;;;;;;;;;;;;;2450:30;;;;;;;;;;;;;;;-1:-1:-1;2512:8:10;2296:236;;;;1415:159;2375:45;;2434:48;;-1:-1:-1;;;;;2512:8:10;;;;2296:236;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2296:236:10;;;2286:247;;49:4:-1;2286:247:10;;;;2256:27;:277;-1:-1:-1;838:227:0;;146:263:-1;;261:2;249:9;240:7;236:23;232:32;229:2;;;-1:-1;;267:12;229:2;89:6;83:13;-1:-1;;;;;5679:5;5285:54;5654:5;5651:35;5641:2;;-1:-1;;5690:12;5641:2;319:74;223:186;-1:-1;;;223:186;2777:661;505:58;;;3077:2;3068:12;;505:58;;;;3179:12;;;505:58;3290:12;;;505:58;3401:12;;;2968:470;3445:1440;2506:66;2486:87;;872:66;2470:2;2592:12;;852:87;2097:66;958:12;;;2077:87;1281:66;2183:12;;;1261:87;1689:66;1367:12;;;1669:87;1775:11;;;4029:856;;838:227:0;;;;;;" + }, + "deployedBytecode": { + "linkReferences": {}, + "object": "0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC26CFECD GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xC26CFECD EQ PUSH2 0xFE JUMPI DUP1 PUSH4 0xD2DF0733 EQ PUSH2 0x106 JUMPI DUP1 PUSH4 0xEE55B968 EQ PUSH2 0x119 JUMPI DUP1 PUSH4 0xFB6961CC EQ PUSH2 0x139 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0xF7D8E39 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x23872F55 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0x48A321D6 EQ PUSH2 0xD6 JUMPI DUP1 PUSH4 0x90C3BC3F EQ PUSH2 0xE9 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA0 PUSH2 0x9B CALLDATASIZE PUSH1 0x4 PUSH2 0x15D7 JUMP JUMPDEST PUSH2 0x141 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1958 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xC9 PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x177C JUMP JUMPDEST PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1AAD JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xE4 CALLDATASIZE PUSH1 0x4 PUSH2 0x165B JUMP JUMPDEST PUSH2 0x4E7 JUMP JUMPDEST PUSH2 0xFC PUSH2 0xF7 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x4FA JUMP JUMPDEST STOP JUMPDEST PUSH2 0xC9 PUSH2 0x5A6 JUMP JUMPDEST PUSH2 0xFC PUSH2 0x114 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x5AC JUMP JUMPDEST PUSH2 0x12C PUSH2 0x127 CALLDATASIZE PUSH1 0x4 PUSH2 0x161E JUMP JUMPDEST PUSH2 0x5DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1979 JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xA8F JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0x186 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D7D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x191 DUP4 PUSH2 0xA95 JUMP JUMPDEST PUSH1 0xF8 SHR SWAP1 POP PUSH1 0x4 DUP2 LT PUSH2 0x1D0 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0xFF AND PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1E1 JUMPI INVALID JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1F1 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x229 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D46 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x237 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x2A8 JUMPI DUP4 MLOAD ISZERO PUSH2 0x276 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1E48 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DB4 JUMP JUMPDEST PUSH1 0x2 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x2B6 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x3BB JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x2F7 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x306 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x329 DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x33E DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x385 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP7 POP PUSH2 0x4CE SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x3 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x3C9 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x49C JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x40A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x419 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x43C DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x451 DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x466 SWAP2 SWAP1 PUSH2 0x1927 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4E2 DUP4 PUSH2 0xB61 JUMP JUMPDEST PUSH2 0xBCF JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4F5 DUP4 PUSH2 0xBDD JUMP JUMPDEST PUSH2 0xC3C JUMP JUMPDEST PUSH2 0x507 DUP6 DUP6 DUP6 DUP6 DUP6 PUSH2 0x5AC JUMP JUMPDEST PUSH1 0x0 SLOAD DUP6 MLOAD PUSH1 0x20 DUP8 ADD MLOAD PUSH1 0x40 DUP1 DUP10 ADD MLOAD SWAP1 MLOAD PUSH32 0xBFC8BFCE00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP5 AND SWAP4 PUSH4 0xBFC8BFCE SWAP4 PUSH2 0x56D SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP10 SWAP1 PUSH1 0x4 ADD PUSH2 0x1E7F JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x587 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x59B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x60 PUSH2 0x5BB DUP7 PUSH1 0x40 ADD MLOAD PUSH2 0x5DB JUMP JUMPDEST DUP1 MLOAD SWAP1 SWAP2 POP ISZERO PUSH2 0x5D3 JUMPI PUSH2 0x5D3 DUP7 DUP3 DUP8 DUP8 DUP8 DUP8 PUSH2 0xC4A JUMP JUMPDEST POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x0 PUSH2 0x5EF DUP4 DUP3 PUSH4 0xFFFFFFFF PUSH2 0xE98 AND JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xB4BE83D500000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x682 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3E228BAE00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x6CE JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x64A3BC1500000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x757 JUMPI PUSH2 0x6DB PUSH2 0x11DB JUMP JUMPDEST DUP4 MLOAD PUSH2 0x6F1 SWAP1 DUP6 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x704 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x16ED JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 DUP1 DUP3 MSTORE DUP2 DUP4 ADD SWAP1 SWAP3 MSTORE SWAP2 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0x723 PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x71B JUMPI SWAP1 POP POP SWAP3 POP DUP1 DUP4 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x746 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x297BB70B00000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x7E8 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x50DDE19000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x834 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x4D0AE54600000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x880 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xE5FA431B00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x8CC JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xA3E2038000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x918 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x7E1D980800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x964 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xDD1C7D1800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x999 JUMPI DUP3 MLOAD PUSH2 0x97F SWAP1 DUP5 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x992 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x154B JUMP JUMPDEST SWAP2 POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 EQ ISZERO PUSH2 0xA89 JUMPI PUSH2 0x9EB PUSH2 0x11DB JUMP JUMPDEST PUSH2 0x9F3 PUSH2 0x11DB JUMP JUMPDEST DUP5 MLOAD PUSH2 0xA09 SWAP1 DUP7 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0xA1C SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x1722 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 ADD SWAP1 SWAP3 MSTORE SWAP3 SWAP5 POP SWAP1 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0xA3F PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0xA37 JUMPI SWAP1 POP POP SWAP4 POP DUP2 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0xA62 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP DUP1 DUP5 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0xA7B JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP POP JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x1 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0xAD1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CE9 JUMP JUMPDEST DUP2 PUSH1 0x1 DUP4 MLOAD SUB DUP2 MLOAD DUP2 LT PUSH2 0xAE1 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD DUP3 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ADD SWAP1 SWAP3 MSTORE POP PUSH1 0xF8 SWAP1 DUP2 SHR SWAP1 SHL SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO PUSH2 0xB58 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C1E JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP2 DUP2 ADD MLOAD DUP3 MLOAD PUSH1 0x20 SWAP4 DUP5 ADD MLOAD DUP3 MLOAD SWAP3 DUP6 ADD SWAP3 SWAP1 SWAP3 KECCAK256 DUP4 MLOAD PUSH32 0x213C6F636F3EA94E701C0ADF9B2624AA45A6C694F9A292C094F9A81C24B5DF4C DUP2 MSTORE SWAP5 DUP6 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x2 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST PUSH1 0x40 DUP1 DUP3 ADD MLOAD DUP3 MLOAD PUSH1 0x20 DUP1 DUP6 ADD MLOAD PUSH1 0x60 DUP7 DUP2 ADD MLOAD DUP6 MLOAD SWAP6 DUP5 ADD SWAP6 SWAP1 SWAP6 KECCAK256 DUP7 MLOAD PUSH32 0x2FBCDBAA76BC7589916958AE919DFBEF04D23F6BBF26DE6FF317B32C6CC01E05 DUP2 MSTORE SWAP4 DUP5 ADD SWAP5 SWAP1 SWAP5 MSTORE SWAP5 DUP3 ADD MSTORE SWAP3 DUP4 ADD MSTORE PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 SWAP1 KECCAK256 SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x1 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST ORIGIN PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND EQ PUSH2 0xC99 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CB2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xCA4 DUP8 PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 SWAP3 MSTORE DUP5 MLOAD SWAP3 SWAP4 POP SWAP2 SWAP1 JUMPDEST DUP2 DUP2 EQ PUSH2 0xDA5 JUMPI PUSH1 0x0 DUP7 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xCD1 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD SWAP1 POP PUSH2 0xCE3 PUSH2 0x1294 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP11 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 MSTORE POP SWAP1 POP TIMESTAMP DUP3 GT PUSH2 0xD55 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BE7 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xD60 DUP3 PUSH2 0x4E7 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xD81 DUP3 DUP11 DUP8 DUP2 MLOAD DUP2 LT PUSH2 0xD74 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH2 0x141 JUMP JUMPDEST SWAP1 POP PUSH2 0xD93 DUP8 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST SWAP7 POP POP PUSH1 0x1 SWAP1 SWAP4 ADD SWAP3 POP PUSH2 0xCBC SWAP2 POP POP JUMP JUMPDEST POP PUSH2 0xDB6 DUP3 ORIGIN PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST DUP9 MLOAD SWAP1 SWAP3 POP PUSH1 0x0 JUMPDEST DUP2 DUP2 EQ PUSH2 0xE8B JUMPI PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xDE9 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x60 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xE16 JUMPI PUSH2 0xE83 JUMP JUMPDEST PUSH1 0x0 DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xE24 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x40 ADD MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0xE47 DUP3 DUP8 PUSH2 0x10D0 SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST SWAP1 POP DUP1 PUSH2 0xE80 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B0B JUMP JUMPDEST POP POP JUMPDEST PUSH1 0x1 ADD PUSH2 0xDBE JUMP JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x4 ADD DUP4 MLOAD LT ISZERO PUSH2 0xED8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DEB JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 AND SWAP1 JUMP JUMPDEST PUSH1 0x60 DUP2 DUP4 GT ISZERO PUSH2 0xF3F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B42 JUMP JUMPDEST DUP4 MLOAD DUP3 GT ISZERO PUSH2 0xF7A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B79 JUMP JUMPDEST DUP3 DUP3 SUB PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0xFA7 JUMPI PUSH1 0x20 DUP3 ADD DUP2 DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH2 0xFC8 PUSH2 0xFB6 DUP3 PUSH2 0x1111 JUMP JUMPDEST DUP5 PUSH2 0xFC0 DUP8 PUSH2 0x1111 JUMP JUMPDEST ADD DUP4 MLOAD PUSH2 0x1117 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x2 DUP2 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x22 DUP3 ADD MSTORE PUSH1 0x42 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST DUP2 MLOAD PUSH1 0x40 MLOAD PUSH1 0x60 SWAP2 DUP5 SWAP1 PUSH1 0x20 DUP1 DUP3 MUL DUP1 DUP5 ADD DUP3 ADD SWAP3 SWAP2 ADD DUP3 DUP6 LT ISZERO PUSH2 0x105A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BB0 JUMP JUMPDEST DUP3 DUP6 GT ISZERO PUSH2 0x1074 JUMPI PUSH2 0x106D DUP6 DUP6 DUP4 PUSH2 0x1117 JUMP JUMPDEST DUP5 SWAP8 POP DUP8 SWAP4 POP JUMPDEST PUSH1 0x1 DUP3 ADD SWAP2 POP PUSH1 0x20 DUP2 ADD SWAP1 POP DUP1 DUP5 ADD SWAP3 POP DUP3 SWAP5 POP DUP2 DUP9 MSTORE DUP5 PUSH1 0x40 MSTORE DUP7 DUP9 PUSH1 0x1 DUP5 SUB DUP2 MLOAD DUP2 LT PUSH2 0x109F JUMPI INVALID JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND PUSH1 0x20 SWAP3 DUP4 MUL SWAP2 SWAP1 SWAP2 ADD SWAP1 SWAP2 ADD MSTORE POP SWAP6 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP4 MLOAD MUL PUSH1 0x20 DUP5 ADD DUP2 DUP2 ADD DUP2 SWAP3 POP JUMPDEST DUP1 DUP4 LT ISZERO PUSH2 0x1108 JUMPI DUP3 MLOAD DUP1 DUP7 EQ ISZERO PUSH2 0x10FC JUMPI PUSH1 0x1 SWAP5 POP DUP2 SWAP4 POP JUMPDEST POP PUSH1 0x20 DUP4 ADD SWAP3 POP PUSH2 0x10E2 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1141 JUMPI PUSH1 0x1 DUP2 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP4 MLOAD AND DUP2 DUP6 MLOAD AND DUP1 DUP3 OR DUP7 MSTORE POP POP POP PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 EQ ISZERO PUSH2 0x114E JUMPI PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 GT ISZERO PUSH2 0x1188 JUMPI PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP2 MLOAD JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x1180 JUMPI DUP5 MLOAD DUP7 MSTORE PUSH1 0x20 SWAP6 DUP7 ADD SWAP6 SWAP1 SWAP5 ADD SWAP4 PUSH2 0x1165 JUMP JUMPDEST SWAP1 MSTORE POP PUSH2 0x11D6 JUMP JUMPDEST PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP4 MLOAD JUMPDEST DUP2 DUP7 SLT ISZERO PUSH2 0x11D1 JUMPI DUP3 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP3 DUP4 ADD SWAP3 SWAP1 SWAP2 ADD SWAP1 PUSH2 0x1197 JUMP JUMPDEST DUP6 MSTORE POP POP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH2 0x180 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP1 NOT AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x4CE DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x12F0 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1303 PUSH2 0x12FE DUP3 PUSH2 0x1EF8 JUMP JUMPDEST PUSH2 0x1ED1 JUMP JUMPDEST DUP2 DUP2 MSTORE SWAP2 POP PUSH1 0x20 DUP1 DUP4 ADD SWAP1 DUP5 ADD PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1340 JUMPI PUSH2 0x132B DUP8 PUSH1 0x20 DUP5 CALLDATALOAD DUP10 ADD ADD PUSH2 0x134A JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 SWAP3 DUP4 ADD SWAP3 SWAP2 SWAP1 SWAP2 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1313 JUMP JUMPDEST POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x135A JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1368 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x137F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x13A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH2 0x13B7 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x13CE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x13DF DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x13F9 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x1402 DUP2 PUSH2 0x1ED1 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x140F DUP4 DUP4 PUSH2 0x12D5 JUMP JUMPDEST DUP2 MSTORE PUSH2 0x141E DUP4 PUSH1 0x20 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH2 0x1430 DUP4 PUSH1 0x40 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD MSTORE PUSH2 0x1442 DUP4 PUSH1 0x60 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP3 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP3 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP3 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x14A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x14B0 DUP7 DUP4 DUP8 ADD PUSH2 0x1398 JUMP JUMPDEST DUP4 DUP6 ADD MSTORE PUSH2 0x160 SWAP3 POP DUP3 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x14CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x14D9 DUP6 DUP3 DUP7 ADD PUSH2 0x1398 JUMP JUMPDEST DUP3 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x14F6 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x1500 PUSH1 0x60 PUSH2 0x1ED1 JUMP JUMPDEST SWAP1 POP DUP2 CALLDATALOAD DUP2 MSTORE PUSH1 0x20 DUP3 ADD CALLDATALOAD PUSH2 0x1514 DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1533 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x153F DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x155D JUMPI DUP2 DUP3 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1573 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP1 DUP5 ADD DUP6 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1584 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 MLOAD SWAP2 POP PUSH2 0x1594 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP4 DUP2 ADD SWAP1 DUP3 DUP6 ADD DUP7 JUMPDEST DUP6 DUP2 LT ISZERO PUSH2 0x15C9 JUMPI PUSH2 0x15B7 DUP11 DUP9 DUP5 MLOAD DUP9 ADD ADD PUSH2 0x13E6 JUMP JUMPDEST DUP5 MSTORE SWAP3 DUP7 ADD SWAP3 SWAP1 DUP7 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x15A0 JUMP JUMPDEST POP SWAP1 SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x15EA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 CALLDATALOAD SWAP2 POP PUSH1 0x20 DUP4 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1608 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x134A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x1630 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1647 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x166C JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x1683 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x80 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x1695 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x169F PUSH1 0x80 PUSH2 0x1ED1 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD PUSH2 0x16AC DUP2 PUSH2 0x1F8C JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 DUP2 DUP2 ADD CALLDATALOAD SWAP1 DUP5 ADD MSTORE PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x16C9 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x16D5 DUP8 DUP3 DUP5 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP PUSH1 0x60 SWAP1 DUP2 ADD CALLDATALOAD SWAP1 DUP4 ADD MSTORE POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x16FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1716 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x1735 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x174D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1759 DUP7 DUP4 DUP8 ADD PUSH2 0x13E6 JUMP JUMPDEST SWAP4 POP PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x176F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x178E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x17A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x14E5 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x17C8 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x17DF JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x17EB DUP10 DUP4 DUP11 ADD PUSH2 0x14E5 JUMP JUMPDEST SWAP7 POP PUSH1 0x20 SWAP2 POP DUP2 DUP9 ADD CALLDATALOAD PUSH2 0x17FE DUP2 PUSH2 0x1F8C JUMP JUMPDEST SWAP6 POP PUSH1 0x40 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1811 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x181D DUP11 DUP3 DUP12 ADD PUSH2 0x134A JUMP JUMPDEST SWAP6 POP POP PUSH1 0x60 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1831 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 DUP10 ADD DUP11 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1842 JUMPI DUP5 DUP6 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP2 POP PUSH2 0x1852 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP5 DUP2 ADD SWAP1 DUP3 DUP7 ADD DUP7 DUP6 MUL DUP5 ADD DUP8 ADD DUP15 LT ISZERO PUSH2 0x186E JUMPI DUP8 DUP9 REVERT JUMPDEST DUP8 SWAP4 POP JUMPDEST DUP5 DUP5 LT ISZERO PUSH2 0x1890 JUMPI DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x1 SWAP4 SWAP1 SWAP4 ADD SWAP3 SWAP2 DUP7 ADD SWAP2 DUP7 ADD PUSH2 0x1872 JUMP JUMPDEST POP SWAP7 POP POP POP POP PUSH1 0x80 DUP9 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x18A9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x18B6 DUP9 DUP3 DUP10 ADD PUSH2 0x12E0 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 POP SWAP3 SWAP6 SWAP1 SWAP4 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 MSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x18F5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE PUSH1 0x1C DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x3C ADD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x1AA0 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE DUP2 MLOAD PUSH2 0x180 PUSH2 0x19DE DUP8 DUP4 MLOAD PUSH2 0x18C3 JUMP JUMPDEST DUP8 DUP3 ADD MLOAD PUSH2 0x19EE DUP10 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0x1A01 PUSH1 0x40 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0x1A14 PUSH1 0x60 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP9 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP9 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP9 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP9 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD DUP3 DUP3 DUP11 ADD MSTORE PUSH2 0x1A6D DUP4 DUP11 ADD DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 SWAP2 POP DUP2 DUP4 ADD MLOAD DUP9 DUP3 SUB DUP4 DUP11 ADD MSTORE PUSH2 0x1A8A DUP3 DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP9 POP POP POP SWAP5 DUP8 ADD SWAP5 POP POP SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x199F JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x12 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F36355F52455155495245440000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F415050524F56414C5F5349474E4154555245000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x46524F4D5F4C4553535F5448414E5F544F5F5245515549524544000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1C SWAP1 DUP3 ADD MSTORE PUSH32 0x544F5F4C4553535F5448414E5F4C454E4754485F524551554952454400000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x17 SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F465245455F4D454D4F52595F505452000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x10 SWAP1 DUP3 ADD MSTORE PUSH32 0x415050524F56414C5F4558504952454400000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x26 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x15 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F554E535550504F525445440000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F4F524947494E000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x21 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F5448414E5F5A45524F5F4C454E4754485F52455155495245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x4400000000000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494C4C4547414C000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1E SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F475245415445525F5448414E5F305F52455155495245440000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494E56414C4944000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x25 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F345F4C454E4754485F524551 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5549524544000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F305F5245515549524544000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP6 DUP3 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH1 0x80 PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1EB4 PUSH1 0x80 DUP4 ADD DUP6 PUSH2 0x18DD JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x60 DUP5 ADD MSTORE PUSH2 0x1EC6 DUP2 DUP6 PUSH2 0x18DD JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1EF0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F0F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 SWAP1 DUP2 MUL ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F30 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1F77 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1F5F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1F86 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x1FAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xbc 0xdb 0x4a 0xab RETURNDATACOPY BYTE DIV 0xea 0x5c 0xd6 0xc1 CODESIZE SWAP2 GT AND 0xce 0xac EXTCODEHASH 0xac DUP9 0xde NOT SWAP6 0xc4 0xd3 CALLCODE 0x4f 0xdd EXTCODEHASH TIMESTAMP 0xf 0xb6 PUSH13 0x6578706572696D656E74616CF5 STOP CALLDATACOPY ", + "sourceMap": "838:227:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;838:227:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;988:3006:3;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;1646:352:11;;;;;;;;;:::i;:::-;;;;;;;;1996:268:9;;;;;;;;;:::i;1627:801:2:-;;;;;;;;;:::i;:::-;;1870:42:10;;;:::i;2108:917:1:-;;;;;;;;;:::i;3237:1762::-;;;;;;;;;:::i;:::-;;;;;;;;1701:45:10;;;:::i;988:3006:3:-;1097:21;1174:1;1155:9;:16;:20;1134:97;;;;;;;;;;;;;;;;;;;;;;1296:22;1327:23;:9;:21;:23::i;:::-;1321:30;;;-1:-1:-1;1449:29:3;1424:55;;1403:123;;;;;;;;;;;;;;1537:27;1581:16;1567:31;;;;;;;;;;1537:61;-1:-1:-1;1948:21:3;1931:13;:38;;;;;;;;;1927:1717;;;1985:27;;;;;;;;;;;1927:1717;2294:21;2277:13;:38;;;;;;;;;2273:1371;;;2356:16;;:21;2331:97;;;;;;;;;;;;;;2442:27;;;;;;;;;;;2273:1371;2542:20;2525:13;:37;;;;;;;;;2521:1123;;;2603:9;:16;2623:2;2603:22;2578:99;;;;;;;;;;;;;;2691:7;2707:9;2717:1;2707:12;;;;;;;;;;;;;;;;;;2701:19;;;-1:-1:-1;2734:9:3;2746:24;:9;2768:1;2746:24;:21;:24;:::i;:::-;2734:36;-1:-1:-1;2784:9:3;2796:25;:9;2818:2;2796:25;:21;:25;:::i;:::-;2784:37;;2851:102;2878:4;2900:1;2919;2938;2851:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;2851:102:3;;;;;;-1:-1:-1;2967:20:3;;-1:-1:-1;;;;;;2967:20:3;2521:1123;3064:21;3047:13;:38;;;;;;;;;3043:601;;;3126:9;:16;3146:2;3126:22;3101:99;;;;;;;;;;;;;;3214:7;3230:9;3240:1;3230:12;;;;;;;;;;;;;;;;;;3224:19;;;-1:-1:-1;3257:9:3;3269:24;:9;3291:1;3269:24;:21;:24;:::i;:::-;3257:36;-1:-1:-1;3307:9:3;3319:25;:9;3341:2;3319:25;:21;:25;:::i;:::-;3307:37;;3374:225;3505:4;3411:116;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;3411:116:3;;;3401:127;;;;;;3546:1;3565;3584;3374:225;;;;;;;;;;;;;;;;;;;3043:601;3956:31;;;;;;;;;;;988:3006;;;;;:::o;1646:352:11:-;1757:23;1898:61;1924:34;1946:11;1924:21;:34::i;:::-;1898:25;:61::i;1996:268:9:-;2114:20;2165:63;2194:33;2218:8;2194:23;:33::i;:::-;2165:28;:63::i;1627:801:2:-;2008:197;2053:11;2078:8;2100:20;2134:29;2177:18;2008:31;:197::i;:::-;2251:8;;2292:16;;2322:25;;;;2361:16;;;;;2251:170;;;;;:8;;;;;:27;;:170;;2292:16;;2322:25;;2391:20;;2251:170;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2251:170:2;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;2251:170:2;;;;1627:801;;;;;:::o;1870:42:10:-;;;;:::o;2108:917:1:-;2511:30;2544:42;2569:11;:16;;;2544:24;:42::i;:::-;2657:13;;2511:75;;-1:-1:-1;2657:17:1;2653:366;;2758:250;2812:11;2841:6;2865:8;2891:20;2929:29;2976:18;2758:36;:250::i;:::-;2108:917;;;;;;:::o;3237:1762::-;3335:30;3381:15;3399:18;:4;3381:15;3399:18;:15;:18;:::i;:::-;3381:36;-1:-1:-1;3444:31:1;;;3456:19;3444:31;;:87;;-1:-1:-1;3491:40:1;;;3503:28;3491:40;3444:87;:142;;;-1:-1:-1;3547:39:1;;;3559:27;3547:39;3444:142;3427:1543;;;3647:27;;:::i;:::-;3720:11;;3706:26;;3720:4;;3717:1;;3706:26;:10;:26;:::i;:::-;3678:102;;;;;;;;;;;;;;3803:23;;;3824:1;3803:23;;;;;;;;;3646:134;;-1:-1:-1;3803:23:1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;3794:32;;3852:5;3840:6;3847:1;3840:9;;;;;;;;;;;;;:17;;;;3427:1543;;;;3891:38;;;3903:26;3891:38;;:101;;-1:-1:-1;3945:47:1;;;3957:35;3945:47;3891:101;:163;;;-1:-1:-1;4008:46:1;;;4020:34;4008:46;3891:163;:217;;;-1:-1:-1;4070:38:1;;;4082:26;4070:38;3891:217;:280;;;-1:-1:-1;4124:47:1;;;4136:35;4124:47;3891:280;:335;;;-1:-1:-1;4187:39:1;;;4199:27;4187:39;3891:335;:399;;;-1:-1:-1;4242:48:1;;;4254:36;4242:48;3891:399;3874:1096;;;4439:11;;4425:26;;4439:4;;4436:1;;4425:26;:10;:26;:::i;:::-;4397:104;;;;;;;;;;;;;;4386:115;;3874:1096;;;4522:33;;;4534:21;4522:33;4518:452;;;4616:31;;:::i;:::-;4649:32;;:::i;:::-;4727:11;;4713:26;;4727:4;;4724:1;;4713:26;:10;:26;:::i;:::-;4685:118;;;;;;;;;;;;;;4865:23;;;4886:1;4865:23;;;;;;;;;4615:188;;-1:-1:-1;4615:188:1;;-1:-1:-1;4865:23:1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;4856:32;;4914:9;4902:6;4909:1;4902:9;;;;;;;;;;;;;:21;;;;4949:10;4937:6;4944:1;4937:9;;;;;;;;;;;;;:22;;;;4518:452;;;-1:-1:-1;3237:1762:1;;;:::o;1701:45:10:-;;;;:::o;8315:448:21:-;8399:13;8460:1;8449;:8;:12;8428:92;;;;;;;;;;;;;;8568:1;8581;8570;:8;:12;8568:15;;;;;;;;;;;;8682:8;;8678:16;;8707:17;;;-1:-1:-1;8568:15:21;;;;;;;8315:448::o;13292:490::-;13413:14;13476:5;13484:2;13476:10;13464:1;:8;:22;;13443:107;;;;;;;;;;;;;;-1:-1:-1;13729:13:21;13631:2;13729:13;13723:20;;13292:490::o;2245:1415:11:-;2479:16;;;;;2520;;2570:25;;;;;2994:11;;2979:13;;;2969:37;;;;3074:9;;1028:66;3097:26;;3223:15;;;3216:29;;;;3368:42;3349:62;;;3332:15;;;3325:87;;;;2459:17;3450:15;;3443:33;3617:3;3599:22;;;2245:1415::o;3216:204:10:-;3318:14;3355:58;3373:27;;3402:10;3355:17;:58::i;2604:1658:9:-;2857:29;;;;;2915:17;;2968:24;;;;;2821:33;3042:38;;;;3589:27;;3558:29;;;3548:69;;;;3685:9;;1121:66;3708:26;;3802:15;;;3795:33;;;;3883:15;;;3876:40;3971:15;;;3964:49;4080:3;4068:16;;4061:55;4219:3;4201:22;;2604:1658;;;:::o;2765:210:10:-;2870:14;2907:61;2925:30;;2957:10;2907:17;:61::i;5691:2759:1:-;6162:9;:21;;;;6141:82;;;;;;;;;;;;;;6265:23;6291:31;6310:11;6291:18;:31::i;:::-;6425:16;;;6439:1;6425:16;;;;;;;;;6479:25;;6265:57;;-1:-1:-1;6425:16:1;6479:25;6514:1147;6539:16;6534:1;:21;6514:1147;;6615:44;6662:29;6692:1;6662:32;;;;;;;;;;;;;;6615:79;;6708:35;;:::i;:::-;6746:266;;;;;;;;6794:8;6746:266;;;;;;6837:15;6746:266;;;;6892:20;6746:266;;;;6961:36;6746:266;;;6708:304;;7200:15;7161:36;:54;7074:191;;;;;;;;;;;;;;7344:20;7367:36;7394:8;7367:26;:36::i;:::-;7344:59;;7417:29;7449:53;7466:12;7480:18;7499:1;7480:21;;;;;;;;;;;;;;7449:16;:53::i;:::-;7417:85;-1:-1:-1;7597:53:1;:23;7417:85;7597:53;:30;:53;:::i;:::-;7571:79;-1:-1:-1;;6557:3:1;;;;;-1:-1:-1;6514:1147:1;;-1:-1:-1;;6514:1147:1;;-1:-1:-1;7773:41:1;:23;7804:9;7773:41;:30;:41;:::i;:::-;7848:13;;7747:67;;-1:-1:-1;7825:20:1;7871:573;7896:12;7891:1;:17;7871:573;;8042:1;8007:37;;:6;8014:1;8007:9;;;;;;;;;;;;;;:23;;;:37;;;8003:84;;;8064:8;;8003:84;8178:23;8204:6;8211:1;8204:9;;;;;;;;;;;;;;:29;;;8178:55;;8247:20;8270:49;8303:15;8270:23;:32;;:49;;;;:::i;:::-;8247:72;;8358:15;8333:100;;;;;;;;;;;;;;7871:573;;;7910:3;;7871:573;;;;5691:2759;;;;;;;;;;:::o;15595:687:21:-;15715:13;15777:5;15785:1;15777:9;15765:1;:8;:21;;15744:105;;;;;;;;;;;;;;-1:-1:-1;16023:13:21;15926:2;16023:13;16017:20;16176:66;16164:79;;15595:687::o;6453:617::-;6587:19;6651:2;6643:4;:10;;6622:83;;;;;;;;;;;;;;6742:1;:8;6736:2;:14;;6715:89;;;;;;;;;;;;;;6905:4;6900:2;:9;6890:20;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;6890:20:21;87:34:-1;135:17;;-1:-1;6890:20:21;;6881:29;;6920:120;6941:23;:6;:21;:23::i;:::-;6999:4;6978:18;:1;:16;:18::i;:::-;:25;7017:6;:13;6920:7;:120::i;:::-;6453:617;;;;;:::o;3701:890:10:-;4130:2;4124:9;4162:66;4147:82;;4279:1;4267:14;;4260:40;;;;4397:2;4385:15;;4378:35;4549:2;4531:21;;;3701:890::o;1089:2102:20:-;1437:19;;1586:4;1580:11;1208:16;;1437:12;;1509:2;:23;;;1675:45;;;;;;1437:19;1503:30;2075:32;;;;2054:102;;;;;;;;;;;;;;2410:18;2397:10;:31;2393:273;;;2444:78;2461:10;2473:20;2495:26;2444:16;:78::i;:::-;2579:10;2563:26;;2630:12;2606:36;;2545:111;2734:1;2712:23;;;;2775:2;2745:32;;;;2831:26;2808:20;:49;2787:70;;2880:18;2867:31;;2990:18;2976:12;2969:40;3071:10;3065:4;3058:24;3140:15;3101:12;3135:1;3114:18;:22;3101:36;;;;;;;;:54;;;;:36;;;;;;;;;;;:54;-1:-1:-1;3172:12:20;;1089:2102;-1:-1:-1;;;;;;1089:2102:20:o;3430:1034::-;3542:12;3685:2;3670:12;3664:19;3660:28;3798:2;3784:12;3780:21;3910:12;3890:18;3886:37;3984:18;3976:26;;3971:453;4010:16;4007:1;4004:23;3971:453;;;4129:1;4123:8;4225:12;4217:6;4214:24;4211:2;;;4315:1;4304:12;;4376:16;4371:21;;4211:2;;4041;4038:1;4034:10;4029:15;;3971:453;;;-1:-1:-1;;;3430:1034:20;;;;:::o;1341:228:21:-;1520:2;1509:14;;1341:228::o;1808:4337::-;1958:2;1949:6;:11;1945:4194;;;2247:1;2237:6;2233:2;2229:15;2224:3;2220:25;2216:33;2298:4;2294:9;2285:6;2279:13;2275:29;2347:4;2340;2334:11;2330:22;2388:1;2385;2382:8;2376:4;2369:22;;;;2186:219;;;2509:4;2499:6;:14;2495:59;;;2533:7;;2495:59;3243:4;3234:6;:13;3230:2899;;;3569:2;3561:6;3557:15;3547:25;;3617:6;3609;3605:19;3667:6;3661:4;3657:17;3974:4;3968:11;4242:198;4260:4;4252:6;4249:16;4242:198;;;4308:13;;4295:27;;4369:2;4405:13;;;;4357:15;;;;4242:198;;;4529:18;;-1:-1:-1;3276:1289:21;;;4810:2;4802:6;4798:15;4788:25;;4858:6;4850;4846:19;4908:6;4902:4;4898:17;5218:6;5212:13;5797:191;5814:4;5808;5804:15;5797:191;;;5862:11;;5849:25;;5907:13;;;;;5953;;;;5797:191;;;6078:19;;-1:-1:-1;;4612:1503:21;1808:4337;;;:::o;838:227:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;142:134:-1:-;220:13;;238:33;220:13;238:33;;299:693;;421:3;414:4;406:6;402:17;398:27;388:2;;-1:-1;;429:12;388:2;476:6;463:20;498:85;513:69;575:6;513:69;;;498:85;;;611:21;;;489:94;-1:-1;655:4;668:14;;;;643:17;;763:1;748:238;773:6;770:1;767:13;748:238;;;880:42;918:3;655:4;856:3;843:17;647:6;831:30;;880:42;;;868:55;;655:4;937:14;;;;965;;;;;795:1;788:9;748:238;;;752:14;;;;381:611;;;;;2646:432;;2743:3;2736:4;2728:6;2724:17;2720:27;2710:2;;-1:-1;;2751:12;2710:2;2798:6;2785:20;2820:60;2835:44;2872:6;2835:44;;2820:60;2811:69;;2900:6;2893:5;2886:21;3004:3;2936:4;2995:6;2928;2986:16;;2983:25;2980:2;;;3021:1;;3011:12;2980:2;37105:6;2936:4;2928:6;2924:17;2936:4;2962:5;2958:16;37082:30;37161:1;37143:16;;;2936:4;37143:16;37136:27;2962:5;2703:375;-1:-1;;2703:375;3087:434;;3195:3;3188:4;3180:6;3176:17;3172:27;3162:2;;-1:-1;;3203:12;3162:2;3243:6;3237:13;3265:60;3280:44;3317:6;3280:44;;3265:60;3256:69;;3345:6;3338:5;3331:21;3449:3;3381:4;3440:6;3373;3431:16;;3428:25;3425:2;;;3466:1;;3456:12;3425:2;3476:39;3508:6;3381:4;3407:5;3403:16;3381:4;3373:6;3369:17;3476:39;;;;3155:366;;;;;4981:2334;;5100:5;;5088:9;5083:3;5079:19;5075:31;5072:2;;;-1:-1;;5109:12;5072:2;5137:21;5152:5;5137:21;;;5128:30;;;5247:60;5303:3;5279:22;5247:60;;;5230:15;5223:85;5410:60;5466:3;5377:2;5446:9;5442:22;5410:60;;;5377:2;5396:5;5392:16;5385:86;5580:60;5636:3;5547:2;5616:9;5612:22;5580:60;;;5547:2;5566:5;5562:16;5555:86;5744:60;5800:3;5711:2;5780:9;5776:22;5744:60;;;5711:2;5730:5;5726:16;5719:86;5878:3;5948:9;5944:22;8315:13;5878:3;5898:5;5894:16;5887:86;6046:3;6116:9;6112:22;8315:13;6046:3;6066:5;6062:16;6055:86;6206:3;6276:9;6272:22;8315:13;6206:3;6226:5;6222:16;6215:86;6366:3;6436:9;6432:22;8315:13;6366:3;6386:5;6382:16;6375:86;6539:3;6621:6;6610:9;6606:22;8315:13;6566:5;6559;6555:17;6548:87;;6696:3;6778:6;6767:9;6763:22;8315:13;6723:5;6716;6712:17;6705:87;;6884:3;;6873:9;6869:19;6863:26;6909:18;;6901:6;6898:30;6895:2;;;5216:1;;6931:12;6895:2;6977:65;7038:3;7029:6;7018:9;7014:22;6977:65;;;6969:5;6962;6958:17;6951:92;7135:3;;;;7124:9;7120:19;7114:26;7100:40;;7160:18;7152:6;7149:30;7146:2;;;5216:1;;7182:12;7146:2;;7228:65;7289:3;7280:6;7269:9;7265:22;7228:65;;;7220:5;7213;7209:17;7202:92;;;5066:2249;;;;;7374:719;;7497:4;7485:9;7480:3;7476:19;7472:30;7469:2;;;-1:-1;;7505:12;7469:2;7533:20;7497:4;7533:20;;;7524:29;;8180:6;8167:20;7617:15;7610:74;7754:2;7812:9;7808:22;72:20;97:33;124:5;97:33;;;7754:2;7769:16;;7762:75;7926:2;7911:18;;7898:32;7950:18;7939:30;;7936:2;;;7603:1;;7972:12;7936:2;8017:54;8067:3;8058:6;8047:9;8043:22;8017:54;;;7926:2;8003:5;7999:16;7992:80;;7463:630;;;;;8378:422;;8533:2;;8521:9;8512:7;8508:23;8504:32;8501:2;;;8549:1;8546;8539:12;8501:2;8590:17;8584:24;8628:18;8620:6;8617:30;8614:2;;;8660:1;8657;8650:12;8614:2;8767:6;8756:9;8752:22;1175:3;1168:4;1160:6;1156:17;1152:27;1142:2;;1193:1;1190;1183:12;1142:2;1223:6;1217:13;1203:27;;1245:95;1260:79;1332:6;1260:79;;1245:95;1368:21;;;1425:14;;;;1400:17;;;1511:10;1505:256;1530:6;1527:1;1524:13;1505:256;;;1630:67;1693:3;1412:4;1606:3;1600:10;1404:6;1588:23;;1630:67;;;1618:80;;1712:14;;;;1740;;;;1552:1;1545:9;1505:256;;;-1:-1;8670:114;;8495:305;-1:-1;;;;;;;;8495:305;8807:470;;;8937:2;8925:9;8916:7;8912:23;8908:32;8905:2;;;-1:-1;;8943:12;8905:2;2588:6;2575:20;8995:63;;9123:2;9112:9;9108:18;9095:32;9147:18;9139:6;9136:30;9133:2;;;-1:-1;;9169:12;9133:2;9199:62;9253:7;9244:6;9233:9;9229:22;9199:62;;;9189:72;;;8899:378;;;;;;9284:345;;9397:2;9385:9;9376:7;9372:23;9368:32;9365:2;;;-1:-1;;9403:12;9365:2;9461:17;9448:31;9499:18;9491:6;9488:30;9485:2;;;-1:-1;;9521:12;9485:2;9551:62;9605:7;9596:6;9585:9;9581:22;9551:62;;;9541:72;9359:270;-1:-1;;;;9359:270;9636:399;;9776:2;9764:9;9755:7;9751:23;9747:32;9744:2;;;9792:1;9789;9782:12;9744:2;9840:17;9827:31;9878:18;;9870:6;9867:30;9864:2;;;9910:1;9907;9900:12;9864:2;10002:6;9991:9;9987:22;4159:4;4147:9;4142:3;4138:19;4134:30;4131:2;;;4177:1;4174;4167:12;4131:2;4195:20;4159:4;4195:20;;;4186:29;;85:6;72:20;97:33;124:5;97:33;;;4276:74;;9776:2;4476:22;;;2575:20;4437:16;;;4430:75;4610:2;4595:18;;4582:32;4623:30;;;4620:2;;;4666:1;4663;4656:12;4620:2;4701:54;4751:3;4742:6;4731:9;4727:22;4701:54;;;4610:2;4683:16;;4676:80;-1:-1;4842:2;4896:22;;;8167:20;4857:16;;;4850:75;-1:-1;4687:5;9738:297;-1:-1;;;9738:297;10042:380;;10176:2;10164:9;10155:7;10151:23;10147:32;10144:2;;;-1:-1;;10182:12;10144:2;10233:17;10227:24;10271:18;10263:6;10260:30;10257:2;;;-1:-1;;10293:12;10257:2;10323:83;10398:7;10389:6;10378:9;10374:22;10323:83;;10429:633;;;10599:2;10587:9;10578:7;10574:23;10570:32;10567:2;;;-1:-1;;10605:12;10567:2;10656:17;10650:24;10694:18;;10686:6;10683:30;10680:2;;;-1:-1;;10716:12;10680:2;10746:83;10821:7;10812:6;10801:9;10797:22;10746:83;;;10736:93;;10887:2;10876:9;10872:18;10866:25;10852:39;;10911:18;10903:6;10900:30;10897:2;;;-1:-1;;10933:12;10897:2;;10963:83;11038:7;11029:6;11018:9;11014:22;10963:83;;11069:395;;11207:2;11195:9;11186:7;11182:23;11178:32;11175:2;;;-1:-1;;11213:12;11175:2;11271:17;11258:31;11309:18;11301:6;11298:30;11295:2;;;-1:-1;;11331:12;11295:2;11361:87;11440:7;11431:6;11420:9;11416:22;11361:87;;11471:1283;;;;;;11741:3;11729:9;11720:7;11716:23;11712:33;11709:2;;;11758:1;11755;11748:12;11709:2;11806:17;11793:31;11844:18;;11836:6;11833:30;11830:2;;;11876:1;11873;11866:12;11830:2;11896:87;11975:7;11966:6;11955:9;11951:22;11896:87;;;11886:97;;12020:2;;;;12063:9;12059:22;72:20;97:33;124:5;97:33;;;12028:63;-1:-1;12156:2;12141:18;;12128:32;12169:30;;;12166:2;;;12212:1;12209;12202:12;12166:2;12232:62;12286:7;12277:6;12266:9;12262:22;12232:62;;;12222:72;;;12359:2;12348:9;12344:18;12331:32;12383:18;12375:6;12372:30;12369:2;;;12415:1;12412;12405:12;12369:2;12496:6;12485:9;12481:22;1910:3;1903:4;1895:6;1891:17;1887:27;1877:2;;1928:1;1925;1918:12;1877:2;1965:6;1952:20;1938:34;;1987:80;2002:64;2059:6;2002:64;;1987:80;2095:21;;;2152:14;;;;2127:17;;;2241;;;2232:27;;;;2229:36;-1:-1;2226:2;;;2278:1;2275;2268:12;2226:2;2294:10;;;2288:206;2313:6;2310:1;2307:13;2288:206;;;8167:20;;2381:50;;2335:1;2328:9;;;;;2445:14;;;;2473;;2288:206;;;-1:-1;12425:88;-1:-1;;;;12578:3;12563:19;;12550:33;;-1:-1;12592:30;;;12589:2;;;12635:1;12632;12625:12;12589:2;;12655:83;12730:7;12721:6;12710:9;12706:22;12655:83;;;12645:93;;;11703:1051;;;;;;;;;13003:103;36801:42;36790:54;13064:37;;13058:48;14579:343;;14721:5;35317:12;35837:6;35832:3;35825:19;14814:52;14859:6;35874:4;35869:3;35865:14;35874:4;14840:5;14836:16;14814:52;;;37623:2;37603:14;37619:7;37599:28;14878:39;;;;35874:4;14878:39;;14669:253;-1:-1;;14669:253;24577:511;16636:66;16616:87;;16600:2;16722:12;;14371:37;;;;25051:12;;;24785:303;25095:213;36801:42;36790:54;;;;13064:37;;25213:2;25198:18;;25184:124;25315:437;;25521:2;;25510:9;25506:18;25561:20;25542:17;25535:47;25596:146;13542:5;35317:12;35837:6;35832:3;35825:19;35865:14;25510:9;35865:14;13554:112;;35865:14;13731:4;13723:6;13719:17;25510:9;13710:27;;13698:39;;35185:4;13827:5;35173:17;-1:-1;13866:387;13891:6;13888:1;13885:13;13866:387;;;13943:20;25510:9;13947:4;13943:20;;13938:3;13931:33;13998:6;13992:13;22086:5;22189:62;22237:13;22167:15;22161:22;22189:62;;;22338:4;22331:5;22327:16;22321:23;22350:63;22407:4;22402:3;22398:14;22384:12;22350:63;;;;35865:14;22500:5;22496:16;22490:23;22519:63;35865:14;22571:3;22567:14;22553:12;22519:63;;;;22670:4;22663:5;22659:16;22653:23;22682:63;22670:4;22734:3;22730:14;22716:12;22682:63;;;;22836:4;22829:5;22825:16;22819:23;22836:4;22900:3;22896:14;14371:37;23002:4;22995:5;22991:16;22985:23;23002:4;23066:3;23062:14;14371:37;23160:4;23153:5;23149:16;23143:23;23160:4;23224:3;23220:14;14371:37;23318:4;23311:5;23307:16;23301:23;23318:4;23382:3;23378:14;14371:37;23489:5;;23482;23478:17;23472:24;23559:5;23554:3;23550:15;14371:37;;23645:5;;23638;23634:17;23628:24;23715:5;23710:3;23706:15;14371:37;;23811:5;;23804;23800:17;23794:24;23855:14;23847:5;23842:3;23838:15;23831:39;23885:67;22086:5;22081:3;22077:15;23933:12;23885:67;;;23877:75;;;24047:5;;;;24040;24036:17;24030:24;24101:3;24095:4;24091:14;24083:5;24078:3;24074:15;24067:39;24121:67;24183:4;24169:12;24121:67;;;14012:110;-1:-1;;;14232:14;;;;-1:-1;;35173:17;;;;13913:1;13906:9;13866:387;;;-1:-1;25588:154;;25492:260;-1:-1;;;;;;;25492:260;25759:213;14371:37;;;25877:2;25862:18;;25848:124;25979:539;14371:37;;;37006:4;36995:16;;;;26338:2;26323:18;;24530:35;26421:2;26406:18;;14371:37;26504:2;26489:18;;14371:37;26177:3;26162:19;;26148:370;26525:407;26716:2;26730:47;;;15818:2;26701:18;;;35825:19;15854:66;35865:14;;;15834:87;15940:12;;;26687:245;26939:407;27130:2;27144:47;;;16191:2;27115:18;;;35825:19;16227:66;35865:14;;;16207:87;16313:12;;;27101:245;27353:407;27544:2;27558:47;;;16973:2;27529:18;;;35825:19;17009:66;35865:14;;;16989:87;17095:12;;;27515:245;27767:407;27958:2;27972:47;;;17346:2;27943:18;;;35825:19;17382:66;35865:14;;;17362:87;17468:12;;;27929:245;28181:407;28372:2;28386:47;;;17719:2;28357:18;;;35825:19;17755:66;35865:14;;;17735:87;17841:12;;;28343:245;28595:407;28786:2;28800:47;;;18092:2;28771:18;;;35825:19;18128:66;35865:14;;;18108:87;18214:12;;;28757:245;29009:407;29200:2;29214:47;;;18465:2;29185:18;;;35825:19;18501:66;35865:14;;;18481:87;18602:66;18588:12;;;18581:88;18688:12;;;29171:245;29423:407;29614:2;29628:47;;;18939:2;29599:18;;;35825:19;18975:66;35865:14;;;18955:87;19061:12;;;29585:245;29837:407;30028:2;30042:47;;;19312:2;30013:18;;;35825:19;19348:66;35865:14;;;19328:87;19434:12;;;29999:245;30251:407;30442:2;30456:47;;;19685:2;30427:18;;;35825:19;19721:66;35865:14;;;19701:87;19822:66;19808:12;;;19801:88;19908:12;;;30413:245;30665:407;30856:2;30870:47;;;20159:2;30841:18;;;35825:19;20195:66;35865:14;;;20175:87;20281:12;;;30827:245;31079:407;31270:2;31284:47;;;20532:2;31255:18;;;35825:19;20568:66;35865:14;;;20548:87;20654:12;;;31241:245;31493:407;31684:2;31698:47;;;20905:2;31669:18;;;35825:19;20941:66;35865:14;;;20921:87;21027:12;;;31655:245;31907:407;32098:2;32112:47;;;21278:2;32083:18;;;35825:19;21314:66;35865:14;;;21294:87;21415:66;21401:12;;;21394:88;21501:12;;;32069:245;32321:407;32512:2;32526:47;;;21752:2;32497:18;;;35825:19;21788:66;35865:14;;;21768:87;21874:12;;;32483:245;32735:707;;14401:5;14378:3;14371:37;36801:42;13094:5;36790:54;33134:2;33123:9;33119:18;13064:37;32969:3;33171:2;33160:9;33156:18;33149:48;33211:72;32969:3;32958:9;32954:19;33269:6;33211:72;;;33331:9;33325:4;33321:20;33316:2;33305:9;33301:18;33294:48;33356:76;33427:4;33418:6;33356:76;;;33348:84;32940:502;-1:-1;;;;;;;32940:502;33449:256;33511:2;33505:9;33537:17;;;33612:18;33597:34;;33633:22;;;33594:62;33591:2;;;33669:1;;33659:12;33591:2;33511;33678:22;33489:216;;-1:-1;33489:216;33712:263;;33876:18;33868:6;33865:30;33862:2;;;-1:-1;;33898:12;33862:2;-1:-1;33937:4;33925:17;;;33955:15;;33799:176;34527:254;;34666:18;34658:6;34655:30;34652:2;;;-1:-1;;34688:12;34652:2;-1:-1;34742:4;34719:17;34738:9;34715:33;34771:4;34761:15;;34589:192;37178:268;37243:1;37250:101;37264:6;37261:1;37258:13;37250:101;;;37331:11;;;37325:18;37312:11;;;37305:39;37286:2;37279:10;37250:101;;;37366:6;37363:1;37360:13;37357:2;;;37243:1;37422:6;37417:3;37413:16;37406:27;37357:2;;37227:219;;;;37640:117;36801:42;37727:5;36790:54;37702:5;37699:35;37689:2;;37748:1;;37738:12;37689:2;37683:74;" } } }, + "sources": { + "src/Coordinator.sol": { + "id": 0 + }, + "src/libs/LibConstants.sol": { + "id": 8 + }, + "src/interfaces/ITransactions.sol": { + "id": 7 + }, + "src/MixinSignatureValidator.sol": { + "id": 3 + }, + "@0x/contracts-utils/contracts/src/LibBytes.sol": { + "id": 21 + }, + "src/mixins/MSignatureValidator.sol": { + "id": 13 + }, + "src/interfaces/ISignatureValidator.sol": { + "id": 6 + }, + "src/MixinCoordinatorApprovalVerifier.sol": { + "id": 1 + }, + "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": { + "id": 18 + }, + "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": { + "id": 19 + }, + "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": { + "id": 17 + }, + "@0x/contracts-utils/contracts/src/LibAddressArray.sol": { + "id": 20 + }, + "src/libs/LibCoordinatorApproval.sol": { + "id": 9 + }, + "src/libs/LibEIP712Domain.sol": { + "id": 10 + }, + "src/libs/LibZeroExTransaction.sol": { + "id": 11 + }, + "src/mixins/MCoordinatorApprovalVerifier.sol": { + "id": 12 + }, + "src/interfaces/ICoordinatorApprovalVerifier.sol": { + "id": 4 + }, + "src/MixinCoordinatorCore.sol": { + "id": 2 + }, + "src/interfaces/ICoordinatorCore.sol": { + "id": 5 + } + }, + "sourceCodes": { + "src/Coordinator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibConstants.sol\";\nimport \"./MixinSignatureValidator.sol\";\nimport \"./MixinCoordinatorApprovalVerifier.sol\";\nimport \"./MixinCoordinatorCore.sol\";\n\n\n// solhint-disable no-empty-blocks\ncontract Coordinator is\n LibConstants,\n MixinSignatureValidator,\n MixinCoordinatorApprovalVerifier,\n MixinCoordinatorCore\n{\n constructor (address _exchange)\n public\n LibConstants(_exchange)\n {}\n}\n", + "src/libs/LibConstants.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ITransactions.sol\";\n\n\ncontract LibConstants {\n\n // solhint-disable-next-line var-name-mixedcase\n ITransactions internal EXCHANGE;\n\n constructor (address _exchange)\n public\n {\n EXCHANGE = ITransactions(_exchange);\n }\n}\n", + "src/interfaces/ITransactions.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\npragma solidity ^0.5.5;\n\n\ncontract ITransactions {\n\n /// @dev Executes an exchange method call in the context of signer.\n /// @param salt Arbitrary number to ensure uniqueness of transaction hash.\n /// @param signerAddress Address of transaction signer.\n /// @param data AbiV2 encoded calldata.\n /// @param signature Proof of signer transaction by signer.\n function executeTransaction(\n uint256 salt,\n address signerAddress,\n bytes calldata data,\n bytes calldata signature\n )\n external;\n}\n", + "src/MixinSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\n\n\ncontract MixinSignatureValidator is\n MSignatureValidator\n{\n using LibBytes for bytes;\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress)\n {\n require(\n signature.length > 0,\n \"LENGTH_GREATER_THAN_0_REQUIRED\"\n );\n\n // Pop last byte off of signature byte array.\n uint8 signatureTypeRaw = uint8(signature.popLastByte());\n\n // Ensure signature is supported\n require(\n signatureTypeRaw < uint8(SignatureType.NSignatureTypes),\n \"SIGNATURE_UNSUPPORTED\"\n );\n\n SignatureType signatureType = SignatureType(signatureTypeRaw);\n\n // Always illegal signature.\n // This is always an implicit option since a signer can create a\n // signature array with invalid type or length. We may as well make\n // it an explicit option. This aids testing and analysis. It is\n // also the initialization value for the enum type.\n if (signatureType == SignatureType.Illegal) {\n revert(\"SIGNATURE_ILLEGAL\");\n\n // Always invalid signature.\n // Like Illegal, this is always implicitly available and therefore\n // offered explicitly. It can be implicitly created by providing\n // a correctly formatted but incorrect signature.\n } else if (signatureType == SignatureType.Invalid) {\n require(\n signature.length == 0,\n \"LENGTH_0_REQUIRED\"\n );\n revert(\"SIGNATURE_INVALID\");\n\n // Signature using EIP712\n } else if (signatureType == SignatureType.EIP712) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n hash,\n v,\n r,\n s\n );\n return signerAddress;\n\n // Signed using web3.eth_sign\n } else if (signatureType == SignatureType.EthSign) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n keccak256(abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n32\",\n hash\n )),\n v,\n r,\n s\n );\n return signerAddress;\n }\n\n // Anything else is illegal (We do not return false because\n // the signature may actually be valid, just not in a format\n // that we currently support. In this case returning false\n // may lead the caller to incorrectly believe that the\n // signature was invalid.)\n revert(\"SIGNATURE_UNSUPPORTED\");\n }\n}\n", + "@0x/contracts-utils/contracts/src/LibBytes.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\nlibrary LibBytes {\n\n using LibBytes for bytes;\n\n /// @dev Gets the memory address for a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of byte array. This\n /// points to the header of the byte array which contains\n /// the length.\n function rawAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := input\n }\n return memoryAddress;\n }\n \n /// @dev Gets the memory address for the contents of a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of the contents of the byte array.\n function contentAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := add(input, 32)\n }\n return memoryAddress;\n }\n\n /// @dev Copies `length` bytes from memory location `source` to `dest`.\n /// @param dest memory address to copy bytes to.\n /// @param source memory address to copy bytes from.\n /// @param length number of bytes to copy.\n function memCopy(\n uint256 dest,\n uint256 source,\n uint256 length\n )\n internal\n pure\n {\n if (length < 32) {\n // Handle a partial word by reading destination and masking\n // off the bits we are interested in.\n // This correctly handles overlap, zero lengths and source == dest\n assembly {\n let mask := sub(exp(256, sub(32, length)), 1)\n let s := and(mload(source), not(mask))\n let d := and(mload(dest), mask)\n mstore(dest, or(s, d))\n }\n } else {\n // Skip the O(length) loop when source == dest.\n if (source == dest) {\n return;\n }\n\n // For large copies we copy whole words at a time. The final\n // word is aligned to the end of the range (instead of after the\n // previous) to handle partial words. So a copy will look like this:\n //\n // ####\n // ####\n // ####\n // ####\n //\n // We handle overlap in the source and destination range by\n // changing the copying direction. This prevents us from\n // overwriting parts of source that we still need to copy.\n //\n // This correctly handles source == dest\n //\n if (source > dest) {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because it\n // is easier to compare with in the loop, and these\n // are also the addresses we need for copying the\n // last bytes.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the last 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the last bytes in\n // source already due to overlap.\n let last := mload(sEnd)\n\n // Copy whole words front to back\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} lt(source, sEnd) {} {\n mstore(dest, mload(source))\n source := add(source, 32)\n dest := add(dest, 32)\n }\n \n // Write the last 32 bytes\n mstore(dEnd, last)\n }\n } else {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because those\n // are the starting points when copying a word at the end.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the first 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the first bytes in\n // source already due to overlap.\n let first := mload(source)\n\n // Copy whole words back to front\n // We use a signed comparisson here to allow dEnd to become\n // negative (happens when source and dest < 32). Valid\n // addresses in local memory will never be larger than\n // 2**255, so they can be safely re-interpreted as signed.\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} slt(dest, dEnd) {} {\n mstore(dEnd, mload(sEnd))\n sEnd := sub(sEnd, 32)\n dEnd := sub(dEnd, 32)\n }\n \n // Write the first 32 bytes\n mstore(dest, first)\n }\n }\n }\n }\n\n /// @dev Returns a slices from a byte array.\n /// @param b The byte array to take a slice from.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n function slice(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure and copy contents\n result = new bytes(to - from);\n memCopy(\n result.contentAddress(),\n b.contentAddress() + from,\n result.length\n );\n return result;\n }\n \n /// @dev Returns a slice from a byte array without preserving the input.\n /// @param b The byte array to take a slice from. Will be destroyed in the process.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted.\n function sliceDestructive(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure around [from, to) in-place.\n assembly {\n result := add(b, from)\n mstore(result, sub(to, from))\n }\n return result;\n }\n\n /// @dev Pops the last byte off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The byte that was popped off.\n function popLastByte(bytes memory b)\n internal\n pure\n returns (bytes1 result)\n {\n require(\n b.length > 0,\n \"GREATER_THAN_ZERO_LENGTH_REQUIRED\"\n );\n\n // Store last byte.\n result = b[b.length - 1];\n\n assembly {\n // Decrement length of byte array.\n let newLen := sub(mload(b), 1)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Pops the last 20 bytes off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The 20 byte address that was popped off.\n function popLast20Bytes(bytes memory b)\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= 20,\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Store last 20 bytes.\n result = readAddress(b, b.length - 20);\n\n assembly {\n // Subtract 20 from byte array length.\n let newLen := sub(mload(b), 20)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Tests equality of two byte arrays.\n /// @param lhs First byte array to compare.\n /// @param rhs Second byte array to compare.\n /// @return True if arrays are the same. False otherwise.\n function equals(\n bytes memory lhs,\n bytes memory rhs\n )\n internal\n pure\n returns (bool equal)\n {\n // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare.\n // We early exit on unequal lengths, but keccak would also correctly\n // handle this.\n return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs);\n }\n\n /// @dev Reads an address from a position in a byte array.\n /// @param b Byte array containing an address.\n /// @param index Index in byte array of address.\n /// @return address from byte array.\n function readAddress(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Read address from array memory\n assembly {\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 20-byte mask to obtain address\n result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n return result;\n }\n\n /// @dev Writes an address into a specific position in a byte array.\n /// @param b Byte array to insert address into.\n /// @param index Index in byte array of address.\n /// @param input Address to put into byte array.\n function writeAddress(\n bytes memory b,\n uint256 index,\n address input\n )\n internal\n pure\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Store address into array memory\n assembly {\n // The address occupies 20 bytes and mstore stores 32 bytes.\n // First fetch the 32-byte word where we'll be storing the address, then\n // apply a mask so we have only the bytes in the word that the address will not occupy.\n // Then combine these bytes with the address and store the 32 bytes back to memory with mstore.\n\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address\n let neighbors := and(\n mload(add(b, index)),\n 0xffffffffffffffffffffffff0000000000000000000000000000000000000000\n )\n \n // Make sure input address is clean.\n // (Solidity does not guarantee this)\n input := and(input, 0xffffffffffffffffffffffffffffffffffffffff)\n\n // Store the neighbors and address into memory\n mstore(add(b, index), xor(input, neighbors))\n }\n }\n\n /// @dev Reads a bytes32 value from a position in a byte array.\n /// @param b Byte array containing a bytes32 value.\n /// @param index Index in byte array of bytes32 value.\n /// @return bytes32 value from byte array.\n function readBytes32(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes32 result)\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n result := mload(add(b, index))\n }\n return result;\n }\n\n /// @dev Writes a bytes32 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes32 to put into byte array.\n function writeBytes32(\n bytes memory b,\n uint256 index,\n bytes32 input\n )\n internal\n pure\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n mstore(add(b, index), input)\n }\n }\n\n /// @dev Reads a uint256 value from a position in a byte array.\n /// @param b Byte array containing a uint256 value.\n /// @param index Index in byte array of uint256 value.\n /// @return uint256 value from byte array.\n function readUint256(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (uint256 result)\n {\n result = uint256(readBytes32(b, index));\n return result;\n }\n\n /// @dev Writes a uint256 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input uint256 to put into byte array.\n function writeUint256(\n bytes memory b,\n uint256 index,\n uint256 input\n )\n internal\n pure\n {\n writeBytes32(b, index, bytes32(input));\n }\n\n /// @dev Reads an unpadded bytes4 value from a position in a byte array.\n /// @param b Byte array containing a bytes4 value.\n /// @param index Index in byte array of bytes4 value.\n /// @return bytes4 value from byte array.\n function readBytes4(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes4 result)\n {\n require(\n b.length >= index + 4,\n \"GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 32 byte length field\n index += 32;\n\n // Read the bytes4 from array memory\n assembly {\n result := mload(add(b, index))\n // Solidity does not require us to clean the trailing bytes.\n // We do it anyway\n result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)\n }\n return result;\n }\n\n /// @dev Reads nested bytes from a specific position.\n /// @dev NOTE: the returned value overlaps with the input value.\n /// Both should be treated as immutable.\n /// @param b Byte array containing nested bytes.\n /// @param index Index of nested bytes.\n /// @return result Nested bytes.\n function readBytesWithLength(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes memory result)\n {\n // Read length of nested bytes\n uint256 nestedBytesLength = readUint256(b, index);\n index += 32;\n\n // Assert length of is valid, given\n // length of nested bytes\n require(\n b.length >= index + nestedBytesLength,\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n \n // Return a pointer to the byte array as it exists inside `b`\n assembly {\n result := add(b, index)\n }\n return result;\n }\n\n /// @dev Inserts bytes at a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes to insert.\n function writeBytesWithLength(\n bytes memory b,\n uint256 index,\n bytes memory input\n )\n internal\n pure\n {\n // Assert length of is valid, given\n // length of input\n require(\n b.length >= index + 32 + input.length, // 32 bytes to store length\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n\n // Copy into \n memCopy(\n b.contentAddress() + index,\n input.rawAddress(), // includes length of \n input.length + 32 // +32 bytes to store length\n );\n }\n\n /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.\n /// @param dest Byte array that will be overwritten with source bytes.\n /// @param source Byte array to copy onto dest bytes.\n function deepCopyBytes(\n bytes memory dest,\n bytes memory source\n )\n internal\n pure\n {\n uint256 sourceLen = source.length;\n // Dest length must be >= source length, or some bytes would not be copied.\n require(\n dest.length >= sourceLen,\n \"GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED\"\n );\n memCopy(\n dest.contentAddress(),\n source.contentAddress(),\n sourceLen\n );\n }\n}\n", + "src/mixins/MSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ISignatureValidator.sol\";\n\n\ncontract MSignatureValidator is\n ISignatureValidator\n{\n // Allowed signature types.\n enum SignatureType {\n Illegal, // 0x00, default value\n Invalid, // 0x01\n EIP712, // 0x02\n EthSign, // 0x03\n NSignatureTypes // 0x04, number of signature types. Always leave at end.\n }\n}\n", + "src/interfaces/ISignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract ISignatureValidator {\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress);\n}\n", + "src/MixinCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol\";\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibAddressArray.sol\";\nimport \"./libs/LibCoordinatorApproval.sol\";\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\n\n\n// solhint-disable avoid-tx-origin\ncontract MixinCoordinatorApprovalVerifier is\n LibExchangeSelectors,\n LibCoordinatorApproval,\n LibZeroExTransaction,\n MSignatureValidator,\n MCoordinatorApprovalVerifier\n{\n using LibBytes for bytes;\n using LibAddressArray for address[];\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view\n {\n // Get the orders from the the Exchange calldata in the 0x transaction\n LibOrder.Order[] memory orders = decodeOrdersFromFillData(transaction.data);\n\n // No approval is required for non-fill methods\n if (orders.length > 0) {\n // Revert if approval is invalid for transaction orders\n assertValidTransactionOrdersApproval(\n transaction,\n orders,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n }\n }\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders)\n {\n bytes4 selector = data.readBytes4(0);\n if (\n selector == FILL_ORDER_SELECTOR ||\n selector == FILL_ORDER_NO_THROW_SELECTOR ||\n selector == FILL_OR_KILL_ORDER_SELECTOR\n ) {\n // Decode single order\n (LibOrder.Order memory order) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order)\n );\n orders = new LibOrder.Order[](1);\n orders[0] = order;\n } else if (\n selector == BATCH_FILL_ORDERS_SELECTOR ||\n selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||\n selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||\n selector == MARKET_SELL_ORDERS_SELECTOR ||\n selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR\n ) {\n // Decode all orders\n // solhint-disable indent\n (orders) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order[])\n );\n } else if (selector == MATCH_ORDERS_SELECTOR) {\n // Decode left and right orders\n (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order, LibOrder.Order)\n );\n\n // Create array of orders\n orders = new LibOrder.Order[](2);\n orders[0] = leftOrder;\n orders[1] = rightOrder;\n }\n return orders;\n }\n\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view\n {\n // Verify that Ethereum tx signer is the same as the approved txOrigin\n require(\n tx.origin == txOrigin,\n \"INVALID_ORIGIN\"\n );\n\n // Hash 0x transaction\n bytes32 transactionHash = getTransactionHash(transaction);\n\n // Create empty list of approval signers\n address[] memory approvalSignerAddresses = new address[](0);\n\n uint256 signaturesLength = approvalSignatures.length;\n for (uint256 i = 0; i != signaturesLength; i++) {\n // Create approval message\n uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i];\n CoordinatorApproval memory approval = CoordinatorApproval({\n txOrigin: txOrigin,\n transactionHash: transactionHash,\n transactionSignature: transactionSignature,\n approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds\n });\n\n // Ensure approval has not expired\n require(\n // solhint-disable-next-line not-rely-on-time\n currentApprovalExpirationTimeSeconds > block.timestamp,\n \"APPROVAL_EXPIRED\"\n );\n\n // Hash approval message and recover signer address\n bytes32 approvalHash = getCoordinatorApprovalHash(approval);\n address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]);\n\n // Add approval signer to list of signers\n approvalSignerAddresses = approvalSignerAddresses.append(approvalSignerAddress);\n }\n\n // Ethereum transaction signer gives implicit signature of approval\n approvalSignerAddresses = approvalSignerAddresses.append(tx.origin);\n\n uint256 ordersLength = orders.length;\n for (uint256 i = 0; i != ordersLength; i++) {\n // Do not check approval if the order's senderAddress is null\n if (orders[i].senderAddress == address(0)) {\n continue;\n }\n\n // Ensure feeRecipient of order has approved this 0x transaction\n address approverAddress = orders[i].feeRecipientAddress;\n bool isOrderApproved = approvalSignerAddresses.contains(approverAddress);\n require(\n isOrderApproved,\n \"INVALID_APPROVAL_SIGNATURE\"\n );\n }\n }\n}\n", + "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibExchangeSelectors {\n\n // solhint-disable max-line-length\n // allowedValidators\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514;\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256(\"allowedValidators(address,address)\"));\n\n // assetProxies\n bytes4 constant internal ASSET_PROXIES_SELECTOR = 0x3fd3c997;\n bytes4 constant internal ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256(\"assetProxies(bytes4)\"));\n\n // batchCancelOrders\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782;\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // batchFillOrKillOrders\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546;\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrders\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b;\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrdersNoThrow\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190;\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // cancelOrder\n bytes4 constant internal CANCEL_ORDER_SELECTOR = 0xd46b02c3;\n bytes4 constant internal CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // cancelOrdersUpTo\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1;\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrdersUpTo(uint256)\"));\n\n // cancelled\n bytes4 constant internal CANCELLED_SELECTOR = 0x2ac12622;\n bytes4 constant internal CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelled(bytes32)\"));\n\n // currentContextAddress\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba;\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256(\"currentContextAddress()\"));\n\n // executeTransaction\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce;\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256(\"executeTransaction(uint256,address,bytes,bytes)\"));\n\n // fillOrKillOrder\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15;\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrder\n bytes4 constant internal FILL_ORDER_SELECTOR = 0xb4be83d5;\n bytes4 constant internal FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrderNoThrow\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae;\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // filled\n bytes4 constant internal FILLED_SELECTOR = 0x288cdc91;\n bytes4 constant internal FILLED_SELECTOR_GENERATOR = bytes4(keccak256(\"filled(bytes32)\"));\n\n // getAssetProxy\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR = 0x60704108;\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"getAssetProxy(bytes4)\"));\n\n // getOrderInfo\n bytes4 constant internal GET_ORDER_INFO_SELECTOR = 0xc75e0a81;\n bytes4 constant internal GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // getOrdersInfo\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc;\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // isValidSignature\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR = 0x93634702;\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256(\"isValidSignature(bytes32,address,bytes)\"));\n\n // marketBuyOrders\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b;\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketBuyOrdersNoThrow\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380;\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrders\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808;\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrdersNoThrow\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18;\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // matchOrders\n bytes4 constant internal MATCH_ORDERS_SELECTOR = 0x3c28d861;\n bytes4 constant internal MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)\"));\n\n // orderEpoch\n bytes4 constant internal ORDER_EPOCH_SELECTOR = 0xd9bfa73e;\n bytes4 constant internal ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256(\"orderEpoch(address,address)\"));\n\n // owner\n bytes4 constant internal OWNER_SELECTOR = 0x8da5cb5b;\n bytes4 constant internal OWNER_SELECTOR_GENERATOR = bytes4(keccak256(\"owner()\"));\n\n // preSign\n bytes4 constant internal PRE_SIGN_SELECTOR = 0x3683ef8e;\n bytes4 constant internal PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256(\"preSign(bytes32,address,bytes)\"));\n\n // preSigned\n bytes4 constant internal PRE_SIGNED_SELECTOR = 0x82c174d0;\n bytes4 constant internal PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256(\"preSigned(bytes32,address)\"));\n\n // registerAssetProxy\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93;\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"registerAssetProxy(address)\"));\n\n // setSignatureValidatorApproval\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68;\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256(\"setSignatureValidatorApproval(address,bool)\"));\n\n // transactions\n bytes4 constant internal TRANSACTIONS_SELECTOR = 0x642f2eaf;\n bytes4 constant internal TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256(\"transactions(bytes32)\"));\n\n // transferOwnership\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256(\"transferOwnership(address)\"));\n}", + "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibEIP712.sol\";\n\n\ncontract LibOrder is\n LibEIP712\n{\n // Hash for the EIP712 Order Schema\n bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"Order(\",\n \"address makerAddress,\",\n \"address takerAddress,\",\n \"address feeRecipientAddress,\",\n \"address senderAddress,\",\n \"uint256 makerAssetAmount,\",\n \"uint256 takerAssetAmount,\",\n \"uint256 makerFee,\",\n \"uint256 takerFee,\",\n \"uint256 expirationTimeSeconds,\",\n \"uint256 salt,\",\n \"bytes makerAssetData,\",\n \"bytes takerAssetData\",\n \")\"\n ));\n\n // A valid order remains fillable until it is expired, fully filled, or cancelled.\n // An order's state is unaffected by external factors, like account balances.\n enum OrderStatus {\n INVALID, // Default value\n INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount\n INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount\n FILLABLE, // Order is fillable\n EXPIRED, // Order has already expired\n FULLY_FILLED, // Order is fully filled\n CANCELLED // Order has been cancelled\n }\n\n // solhint-disable max-line-length\n struct Order {\n address makerAddress; // Address that created the order. \n address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order. \n address feeRecipientAddress; // Address that will recieve fees when order is filled. \n address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.\n uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0. \n uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0. \n uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.\n uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.\n uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires. \n uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash. \n bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.\n bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.\n }\n // solhint-enable max-line-length\n\n struct OrderInfo {\n uint8 orderStatus; // Status that describes order's validity and fillability.\n bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash).\n uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.\n }\n\n /// @dev Calculates Keccak-256 hash of the order.\n /// @param order The order structure.\n /// @return Keccak-256 EIP712 hash of the order.\n function getOrderHash(Order memory order)\n internal\n view\n returns (bytes32 orderHash)\n {\n orderHash = hashEIP712Message(hashOrder(order));\n return orderHash;\n }\n\n /// @dev Calculates EIP712 hash of the order.\n /// @param order The order structure.\n /// @return EIP712 hash of the order.\n function hashOrder(Order memory order)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;\n bytes32 makerAssetDataHash = keccak256(order.makerAssetData);\n bytes32 takerAssetDataHash = keccak256(order.takerAssetData);\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ORDER_SCHEMA_HASH,\n // bytes32(order.makerAddress),\n // bytes32(order.takerAddress),\n // bytes32(order.feeRecipientAddress),\n // bytes32(order.senderAddress),\n // order.makerAssetAmount,\n // order.takerAssetAmount,\n // order.makerFee,\n // order.takerFee,\n // order.expirationTimeSeconds,\n // order.salt,\n // keccak256(order.makerAssetData),\n // keccak256(order.takerAssetData)\n // ));\n\n assembly {\n // Calculate memory addresses that will be swapped out before hashing\n let pos1 := sub(order, 32)\n let pos2 := add(order, 320)\n let pos3 := add(order, 352)\n\n // Backup\n let temp1 := mload(pos1)\n let temp2 := mload(pos2)\n let temp3 := mload(pos3)\n \n // Hash in place\n mstore(pos1, schemaHash)\n mstore(pos2, makerAssetDataHash)\n mstore(pos3, takerAssetDataHash)\n result := keccak256(pos1, 416)\n \n // Restore\n mstore(pos1, temp1)\n mstore(pos2, temp2)\n mstore(pos3, temp3)\n }\n return result;\n }\n}\n", + "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibEIP712 {\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value\n string constant internal EIP712_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value\n string constant internal EIP712_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_DOMAIN_NAME)),\n keccak256(bytes(EIP712_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712Message(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;\n\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct \n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", + "@0x/contracts-utils/contracts/src/LibAddressArray.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibBytes.sol\";\n\n\nlibrary LibAddressArray {\n\n /// @dev Append a new address to an array of addresses.\n /// The `addressArray` may need to be reallocated to make space\n /// for the new address. Because of this we return the resulting\n /// memory location of `addressArray`.\n /// @param addressArray Array of addresses.\n /// @param addressToAppend Address to append.\n /// @return Array of addresses: [... addressArray, addressToAppend]\n function append(address[] memory addressArray, address addressToAppend)\n internal\n pure\n returns (address[] memory)\n {\n // Get stats on address array and free memory\n uint256 freeMemPtr = 0;\n uint256 addressArrayBeginPtr = 0;\n uint256 addressArrayEndPtr = 0;\n uint256 addressArrayLength = addressArray.length;\n uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);\n assembly {\n freeMemPtr := mload(0x40)\n addressArrayBeginPtr := addressArray\n addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)\n }\n\n // Cases for `freeMemPtr`:\n // `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`\n // `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`\n // `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.\n require(\n freeMemPtr >= addressArrayEndPtr,\n \"INVALID_FREE_MEMORY_PTR\"\n );\n\n // If free memory begins at the end of `addressArray`\n // then we can append `addressToAppend` directly.\n // Otherwise, we must copy the array to free memory\n // before appending new values to it.\n if (freeMemPtr > addressArrayEndPtr) {\n LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);\n assembly {\n addressArray := freeMemPtr\n addressArrayBeginPtr := addressArray\n }\n }\n\n // Append `addressToAppend`\n addressArrayLength += 1;\n addressArrayMemSizeInBytes += 32;\n addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;\n freeMemPtr = addressArrayEndPtr;\n assembly {\n // Store new array length\n mstore(addressArray, addressArrayLength)\n\n // Update `freeMemPtr`\n mstore(0x40, freeMemPtr)\n }\n addressArray[addressArrayLength - 1] = addressToAppend;\n return addressArray;\n }\n\n /// @dev Checks if an address array contains the target address.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return True if the addressArray contains the target.\n function contains(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success to true\n success := 1\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return success;\n }\n\n /// @dev Finds the index of an address within an array.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return Existence and index of the target in the array.\n function indexOf(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success, uint256 index)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success and index\n success := 1\n index := div(sub(i, arrayContentsStart), 32)\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return (success, index);\n }\n}\n", + "src/libs/LibCoordinatorApproval.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibCoordinatorApproval is\n LibEIP712Domain\n{\n // Hash for the EIP712 Coordinator approval message\n // keccak256(abi.encodePacked(\n // \"CoordinatorApproval(\",\n // \"address txOrigin,\",\n // \"bytes32 transactionHash,\",\n // \"bytes transactionSignature,\",\n // \"uint256 approvalExpirationTimeSeconds\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05;\n\n struct CoordinatorApproval {\n address txOrigin; // Required signer of Ethereum transaction that is submitting approval.\n bytes32 transactionHash; // EIP712 hash of the transaction.\n bytes transactionSignature; // Signature of the 0x transaction.\n uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the approval expires.\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.\n function getCoordinatorApprovalHash(CoordinatorApproval memory approval)\n public\n view\n returns (bytes32 approvalHash)\n {\n approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval));\n return approvalHash;\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage with no domain separator.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with no domain separator.\n function hashCoordinatorApproval(CoordinatorApproval memory approval)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH;\n bytes memory transactionSignature = approval.transactionSignature;\n address txOrigin = approval.txOrigin;\n bytes32 transactionHash = approval.transactionHash;\n uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH,\n // approval.txOrigin,\n // approval.transactionHash,\n // keccak256(approval.transactionSignature)\n // approval.approvalExpirationTimeSeconds,\n // ));\n\n assembly {\n // Compute hash of transaction signature\n let transactionSignatureHash := keccak256(add(transactionSignature, 32), mload(transactionSignature))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), txOrigin) // txOrigin\n mstore(add(memPtr, 64), transactionHash) // transactionHash\n mstore(add(memPtr, 96), transactionSignatureHash) // transactionSignatureHash\n mstore(add(memPtr, 128), approvalExpirationTimeSeconds) // approvalExpirationTimeSeconds\n // Compute hash\n result := keccak256(memPtr, 160)\n }\n return result;\n }\n}\n", + "src/libs/LibEIP712Domain.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibConstants.sol\";\n\n\ncontract LibEIP712Domain is\n LibConstants\n{\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_NAME = \"0x Protocol Coordinator\";\n\n // EIP712 Domain Version value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = \"1.0.0\";\n\n // EIP712 Domain Name value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data for the Coordinator\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;\n\n // Hash of the EIP712 Domain Separator data for the Exchange\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)),\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n\n EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)),\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)),\n uint256(address(EXCHANGE))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of this contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712CoordinatorMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of the Exchange contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712ExchangeMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.\n /// @param eip712DomainHash Hash of the domain domain separator data.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)\n internal\n pure\n returns (bytes32 result)\n {\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct\n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", + "src/libs/LibZeroExTransaction.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibZeroExTransaction is\n LibEIP712Domain\n{\n // Hash for the EIP712 0x transaction schema\n // keccak256(abi.encodePacked(\n // \"ZeroExTransaction(\",\n // \"uint256 salt,\",\n // \"address signerAddress,\",\n // \"bytes data\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0x213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c;\n\n struct ZeroExTransaction {\n uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash.\n address signerAddress; // Address of transaction signer.\n bytes data; // AbiV2 encoded calldata.\n }\n\n /// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with the domain separator of this contract.\n function getTransactionHash(ZeroExTransaction memory transaction)\n public\n view\n returns (bytes32 transactionHash)\n {\n // Hash the transaction with the domain separator of the Exchange contract.\n transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction));\n return transactionHash;\n }\n\n /// @dev Calculates EIP712 hash of the 0x transaction with no domain separator.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with no domain separator.\n function hashZeroExTransaction(ZeroExTransaction memory transaction)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;\n bytes memory data = transaction.data;\n uint256 salt = transaction.salt;\n address signerAddress = transaction.signerAddress;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,\n // transaction.salt,\n // uint256(transaction.signerAddress),\n // keccak256(transaction.data)\n // ));\n\n assembly {\n // Compute hash of data\n let dataHash := keccak256(add(data, 32), mload(data))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), salt) // salt\n mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress\n mstore(add(memPtr, 96), dataHash) // hash of data\n\n // Compute hash\n result := keccak256(memPtr, 128)\n }\n return result;\n }\n}\n", + "src/mixins/MCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../interfaces/ICoordinatorApprovalVerifier.sol\";\n\n\ncontract MCoordinatorApprovalVerifier is\n ICoordinatorApprovalVerifier\n{\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view;\n}\n", + "src/interfaces/ICoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorApprovalVerifier {\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view;\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders);\n}\n", + "src/MixinCoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./libs/LibConstants.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\nimport \"./interfaces/ICoordinatorCore.sol\";\n\n\ncontract MixinCoordinatorCore is\n LibConstants,\n MCoordinatorApprovalVerifier,\n ICoordinatorCore\n{\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n {\n // Validate that the 0x transaction has been approves by each feeRecipient\n assertValidCoordinatorApprovals(\n transaction,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n\n // Execute the transaction\n EXCHANGE.executeTransaction(\n transaction.salt,\n transaction.signerAddress,\n transaction.data,\n transactionSignature\n );\n }\n}\n", + "src/interfaces/ICoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorCore {\n\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public;\n}\n" + }, + "sourceTreeHashHex": "0xcd3a1dbf858b46a5820dab320baad978613f07ec73d35b6cbbde13c2937bbc04", + "compiler": { + "name": "solc", + "version": "soljson-v0.5.8+commit.23d335f2.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { + "yul": true, + "deduplicate": true, + "cse": true, + "constantOptimizer": true + } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "constantinople", + "remappings": [ + "@0x/contracts-utils=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-utils", + "@0x/contracts-exchange-libs=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-exchange-libs" + ] + } + }, "networks": {} -} +} \ No newline at end of file From 821490b2a1b4886f0d97ba3b84ebdb853f5981b9 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 18:06:41 -0700 Subject: [PATCH 28/53] lint --- packages/order-utils/src/signature_utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index e8f1f88730..87dc66bfbd 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -20,7 +20,6 @@ import * as _ from 'lodash'; import { assert } from './assert'; import { eip712Utils } from './eip712_utils'; import { orderHashUtils } from './order_hash'; -import { transactionHashUtils } from './transaction_hash'; import { TypedDataError } from './types'; import { utils } from './utils'; From 16f0f2fae528202ad039d42e155af88ca78b3eb0 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 18:13:37 -0700 Subject: [PATCH 29/53] remove disallowed fields --- .../artifacts/Coordinator.json | 118 +----------------- 1 file changed, 2 insertions(+), 116 deletions(-) diff --git a/packages/contract-artifacts/artifacts/Coordinator.json b/packages/contract-artifacts/artifacts/Coordinator.json index c8af051309..d7f985e8d9 100644 --- a/packages/contract-artifacts/artifacts/Coordinator.json +++ b/packages/contract-artifacts/artifacts/Coordinator.json @@ -296,9 +296,7 @@ "evm": { "bytecode": { "linkReferences": {}, - "object": "0x60806040523480156200001157600080fd5b506040516020806200235b833981018060405262000033919081019062000252565b600080546001600160a01b0319166001600160a01b0383161790556040516200005f906020016200029f565b60408051601f1981840301815282825280516020918201208383018352601784527f30782050726f746f636f6c20436f6f7264696e61746f720000000000000000009382019390935281518083018352600581527f312e302e300000000000000000000000000000000000000000000000000000009082015290516200012d92917f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236917f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9130910162000284565b60408051601f198184030181529082905280516020918201206001556200015591016200029f565b60408051601f1981840301815282825280516020918201208383018352600b84527f30782050726f746f636f6c0000000000000000000000000000000000000000009382019390935281518083018352600181527f32000000000000000000000000000000000000000000000000000000000000009082015260005491516200023093927ff0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61e927fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5926001600160a01b03909216910162000284565b60408051601f1981840301815291905280516020909101206002555062000360565b6000602082840312156200026557600080fd5b81516001600160a01b03811681146200027d57600080fd5b9392505050565b93845260208401929092526040830152606082015260800190565b7f454950373132446f6d61696e280000000000000000000000000000000000000081527f737472696e67206e616d652c0000000000000000000000000000000000000000600d8201527f737472696e672076657273696f6e2c000000000000000000000000000000000060198201527f6164647265737320766572696679696e67436f6e74726163740000000000000060288201527f2900000000000000000000000000000000000000000000000000000000000000604182015260420190565b611feb80620003706000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH3 0x11 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH3 0x235B DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE PUSH3 0x33 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH3 0x252 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND OR SWAP1 SSTORE PUSH1 0x40 MLOAD PUSH3 0x5F SWAP1 PUSH1 0x20 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0x17 DUP5 MSTORE PUSH32 0x30782050726F746F636F6C20436F6F7264696E61746F72000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x5 DUP2 MSTORE PUSH32 0x312E302E30000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE SWAP1 MLOAD PUSH3 0x12D SWAP3 SWAP2 PUSH32 0x626D101E477FD17DD52AFB3F9AD9EB016BF60F6E377877F34E8F3EA84C930236 SWAP2 PUSH32 0x6C015BD22B4C69690933C1058878EBDFEF31F9AAAE40BBE86D8A09FE1B2972C SWAP2 ADDRESS SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 PUSH1 0x1 SSTORE PUSH3 0x155 SWAP2 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0xB DUP5 MSTORE PUSH32 0x30782050726F746F636F6C000000000000000000000000000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x1 DUP2 MSTORE PUSH32 0x3200000000000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE PUSH1 0x0 SLOAD SWAP2 MLOAD PUSH3 0x230 SWAP4 SWAP3 PUSH32 0xF0F24618F4C4BE1E62E026FB039A20EF96F4495294817D1027FFAA6D1F70E61E SWAP3 PUSH32 0xAD7C5BEF027816A800DA1736444FB58A807EF4C9603B7848673F7E3A68EB14A5 SWAP3 PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP2 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP1 SWAP2 ADD KECCAK256 PUSH1 0x2 SSTORE POP PUSH3 0x360 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH3 0x265 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH3 0x27D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0x20 DUP5 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH32 0x454950373132446F6D61696E2800000000000000000000000000000000000000 DUP2 MSTORE PUSH32 0x737472696E67206E616D652C0000000000000000000000000000000000000000 PUSH1 0xD DUP3 ADD MSTORE PUSH32 0x737472696E672076657273696F6E2C0000000000000000000000000000000000 PUSH1 0x19 DUP3 ADD MSTORE PUSH32 0x6164647265737320766572696679696E67436F6E747261637400000000000000 PUSH1 0x28 DUP3 ADD MSTORE PUSH32 0x2900000000000000000000000000000000000000000000000000000000000000 PUSH1 0x41 DUP3 ADD MSTORE PUSH1 0x42 ADD SWAP1 JUMP JUMPDEST PUSH2 0x1FEB DUP1 PUSH3 0x370 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC26CFECD GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xC26CFECD EQ PUSH2 0xFE JUMPI DUP1 PUSH4 0xD2DF0733 EQ PUSH2 0x106 JUMPI DUP1 PUSH4 0xEE55B968 EQ PUSH2 0x119 JUMPI DUP1 PUSH4 0xFB6961CC EQ PUSH2 0x139 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0xF7D8E39 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x23872F55 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0x48A321D6 EQ PUSH2 0xD6 JUMPI DUP1 PUSH4 0x90C3BC3F EQ PUSH2 0xE9 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA0 PUSH2 0x9B CALLDATASIZE PUSH1 0x4 PUSH2 0x15D7 JUMP JUMPDEST PUSH2 0x141 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1958 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xC9 PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x177C JUMP JUMPDEST PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1AAD JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xE4 CALLDATASIZE PUSH1 0x4 PUSH2 0x165B JUMP JUMPDEST PUSH2 0x4E7 JUMP JUMPDEST PUSH2 0xFC PUSH2 0xF7 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x4FA JUMP JUMPDEST STOP JUMPDEST PUSH2 0xC9 PUSH2 0x5A6 JUMP JUMPDEST PUSH2 0xFC PUSH2 0x114 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x5AC JUMP JUMPDEST PUSH2 0x12C PUSH2 0x127 CALLDATASIZE PUSH1 0x4 PUSH2 0x161E JUMP JUMPDEST PUSH2 0x5DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1979 JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xA8F JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0x186 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D7D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x191 DUP4 PUSH2 0xA95 JUMP JUMPDEST PUSH1 0xF8 SHR SWAP1 POP PUSH1 0x4 DUP2 LT PUSH2 0x1D0 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0xFF AND PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1E1 JUMPI INVALID JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1F1 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x229 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D46 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x237 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x2A8 JUMPI DUP4 MLOAD ISZERO PUSH2 0x276 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1E48 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DB4 JUMP JUMPDEST PUSH1 0x2 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x2B6 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x3BB JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x2F7 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x306 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x329 DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x33E DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x385 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP7 POP PUSH2 0x4CE SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x3 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x3C9 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x49C JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x40A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x419 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x43C DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x451 DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x466 SWAP2 SWAP1 PUSH2 0x1927 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4E2 DUP4 PUSH2 0xB61 JUMP JUMPDEST PUSH2 0xBCF JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4F5 DUP4 PUSH2 0xBDD JUMP JUMPDEST PUSH2 0xC3C JUMP JUMPDEST PUSH2 0x507 DUP6 DUP6 DUP6 DUP6 DUP6 PUSH2 0x5AC JUMP JUMPDEST PUSH1 0x0 SLOAD DUP6 MLOAD PUSH1 0x20 DUP8 ADD MLOAD PUSH1 0x40 DUP1 DUP10 ADD MLOAD SWAP1 MLOAD PUSH32 0xBFC8BFCE00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP5 AND SWAP4 PUSH4 0xBFC8BFCE SWAP4 PUSH2 0x56D SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP10 SWAP1 PUSH1 0x4 ADD PUSH2 0x1E7F JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x587 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x59B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x60 PUSH2 0x5BB DUP7 PUSH1 0x40 ADD MLOAD PUSH2 0x5DB JUMP JUMPDEST DUP1 MLOAD SWAP1 SWAP2 POP ISZERO PUSH2 0x5D3 JUMPI PUSH2 0x5D3 DUP7 DUP3 DUP8 DUP8 DUP8 DUP8 PUSH2 0xC4A JUMP JUMPDEST POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x0 PUSH2 0x5EF DUP4 DUP3 PUSH4 0xFFFFFFFF PUSH2 0xE98 AND JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xB4BE83D500000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x682 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3E228BAE00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x6CE JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x64A3BC1500000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x757 JUMPI PUSH2 0x6DB PUSH2 0x11DB JUMP JUMPDEST DUP4 MLOAD PUSH2 0x6F1 SWAP1 DUP6 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x704 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x16ED JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 DUP1 DUP3 MSTORE DUP2 DUP4 ADD SWAP1 SWAP3 MSTORE SWAP2 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0x723 PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x71B JUMPI SWAP1 POP POP SWAP3 POP DUP1 DUP4 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x746 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x297BB70B00000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x7E8 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x50DDE19000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x834 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x4D0AE54600000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x880 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xE5FA431B00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x8CC JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xA3E2038000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x918 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x7E1D980800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x964 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xDD1C7D1800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x999 JUMPI DUP3 MLOAD PUSH2 0x97F SWAP1 DUP5 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x992 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x154B JUMP JUMPDEST SWAP2 POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 EQ ISZERO PUSH2 0xA89 JUMPI PUSH2 0x9EB PUSH2 0x11DB JUMP JUMPDEST PUSH2 0x9F3 PUSH2 0x11DB JUMP JUMPDEST DUP5 MLOAD PUSH2 0xA09 SWAP1 DUP7 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0xA1C SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x1722 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 ADD SWAP1 SWAP3 MSTORE SWAP3 SWAP5 POP SWAP1 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0xA3F PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0xA37 JUMPI SWAP1 POP POP SWAP4 POP DUP2 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0xA62 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP DUP1 DUP5 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0xA7B JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP POP JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x1 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0xAD1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CE9 JUMP JUMPDEST DUP2 PUSH1 0x1 DUP4 MLOAD SUB DUP2 MLOAD DUP2 LT PUSH2 0xAE1 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD DUP3 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ADD SWAP1 SWAP3 MSTORE POP PUSH1 0xF8 SWAP1 DUP2 SHR SWAP1 SHL SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO PUSH2 0xB58 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C1E JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP2 DUP2 ADD MLOAD DUP3 MLOAD PUSH1 0x20 SWAP4 DUP5 ADD MLOAD DUP3 MLOAD SWAP3 DUP6 ADD SWAP3 SWAP1 SWAP3 KECCAK256 DUP4 MLOAD PUSH32 0x213C6F636F3EA94E701C0ADF9B2624AA45A6C694F9A292C094F9A81C24B5DF4C DUP2 MSTORE SWAP5 DUP6 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x2 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST PUSH1 0x40 DUP1 DUP3 ADD MLOAD DUP3 MLOAD PUSH1 0x20 DUP1 DUP6 ADD MLOAD PUSH1 0x60 DUP7 DUP2 ADD MLOAD DUP6 MLOAD SWAP6 DUP5 ADD SWAP6 SWAP1 SWAP6 KECCAK256 DUP7 MLOAD PUSH32 0x2FBCDBAA76BC7589916958AE919DFBEF04D23F6BBF26DE6FF317B32C6CC01E05 DUP2 MSTORE SWAP4 DUP5 ADD SWAP5 SWAP1 SWAP5 MSTORE SWAP5 DUP3 ADD MSTORE SWAP3 DUP4 ADD MSTORE PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 SWAP1 KECCAK256 SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x1 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST ORIGIN PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND EQ PUSH2 0xC99 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CB2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xCA4 DUP8 PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 SWAP3 MSTORE DUP5 MLOAD SWAP3 SWAP4 POP SWAP2 SWAP1 JUMPDEST DUP2 DUP2 EQ PUSH2 0xDA5 JUMPI PUSH1 0x0 DUP7 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xCD1 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD SWAP1 POP PUSH2 0xCE3 PUSH2 0x1294 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP11 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 MSTORE POP SWAP1 POP TIMESTAMP DUP3 GT PUSH2 0xD55 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BE7 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xD60 DUP3 PUSH2 0x4E7 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xD81 DUP3 DUP11 DUP8 DUP2 MLOAD DUP2 LT PUSH2 0xD74 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH2 0x141 JUMP JUMPDEST SWAP1 POP PUSH2 0xD93 DUP8 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST SWAP7 POP POP PUSH1 0x1 SWAP1 SWAP4 ADD SWAP3 POP PUSH2 0xCBC SWAP2 POP POP JUMP JUMPDEST POP PUSH2 0xDB6 DUP3 ORIGIN PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST DUP9 MLOAD SWAP1 SWAP3 POP PUSH1 0x0 JUMPDEST DUP2 DUP2 EQ PUSH2 0xE8B JUMPI PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xDE9 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x60 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xE16 JUMPI PUSH2 0xE83 JUMP JUMPDEST PUSH1 0x0 DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xE24 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x40 ADD MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0xE47 DUP3 DUP8 PUSH2 0x10D0 SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST SWAP1 POP DUP1 PUSH2 0xE80 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B0B JUMP JUMPDEST POP POP JUMPDEST PUSH1 0x1 ADD PUSH2 0xDBE JUMP JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x4 ADD DUP4 MLOAD LT ISZERO PUSH2 0xED8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DEB JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 AND SWAP1 JUMP JUMPDEST PUSH1 0x60 DUP2 DUP4 GT ISZERO PUSH2 0xF3F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B42 JUMP JUMPDEST DUP4 MLOAD DUP3 GT ISZERO PUSH2 0xF7A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B79 JUMP JUMPDEST DUP3 DUP3 SUB PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0xFA7 JUMPI PUSH1 0x20 DUP3 ADD DUP2 DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH2 0xFC8 PUSH2 0xFB6 DUP3 PUSH2 0x1111 JUMP JUMPDEST DUP5 PUSH2 0xFC0 DUP8 PUSH2 0x1111 JUMP JUMPDEST ADD DUP4 MLOAD PUSH2 0x1117 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x2 DUP2 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x22 DUP3 ADD MSTORE PUSH1 0x42 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST DUP2 MLOAD PUSH1 0x40 MLOAD PUSH1 0x60 SWAP2 DUP5 SWAP1 PUSH1 0x20 DUP1 DUP3 MUL DUP1 DUP5 ADD DUP3 ADD SWAP3 SWAP2 ADD DUP3 DUP6 LT ISZERO PUSH2 0x105A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BB0 JUMP JUMPDEST DUP3 DUP6 GT ISZERO PUSH2 0x1074 JUMPI PUSH2 0x106D DUP6 DUP6 DUP4 PUSH2 0x1117 JUMP JUMPDEST DUP5 SWAP8 POP DUP8 SWAP4 POP JUMPDEST PUSH1 0x1 DUP3 ADD SWAP2 POP PUSH1 0x20 DUP2 ADD SWAP1 POP DUP1 DUP5 ADD SWAP3 POP DUP3 SWAP5 POP DUP2 DUP9 MSTORE DUP5 PUSH1 0x40 MSTORE DUP7 DUP9 PUSH1 0x1 DUP5 SUB DUP2 MLOAD DUP2 LT PUSH2 0x109F JUMPI INVALID JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND PUSH1 0x20 SWAP3 DUP4 MUL SWAP2 SWAP1 SWAP2 ADD SWAP1 SWAP2 ADD MSTORE POP SWAP6 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP4 MLOAD MUL PUSH1 0x20 DUP5 ADD DUP2 DUP2 ADD DUP2 SWAP3 POP JUMPDEST DUP1 DUP4 LT ISZERO PUSH2 0x1108 JUMPI DUP3 MLOAD DUP1 DUP7 EQ ISZERO PUSH2 0x10FC JUMPI PUSH1 0x1 SWAP5 POP DUP2 SWAP4 POP JUMPDEST POP PUSH1 0x20 DUP4 ADD SWAP3 POP PUSH2 0x10E2 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1141 JUMPI PUSH1 0x1 DUP2 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP4 MLOAD AND DUP2 DUP6 MLOAD AND DUP1 DUP3 OR DUP7 MSTORE POP POP POP PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 EQ ISZERO PUSH2 0x114E JUMPI PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 GT ISZERO PUSH2 0x1188 JUMPI PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP2 MLOAD JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x1180 JUMPI DUP5 MLOAD DUP7 MSTORE PUSH1 0x20 SWAP6 DUP7 ADD SWAP6 SWAP1 SWAP5 ADD SWAP4 PUSH2 0x1165 JUMP JUMPDEST SWAP1 MSTORE POP PUSH2 0x11D6 JUMP JUMPDEST PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP4 MLOAD JUMPDEST DUP2 DUP7 SLT ISZERO PUSH2 0x11D1 JUMPI DUP3 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP3 DUP4 ADD SWAP3 SWAP1 SWAP2 ADD SWAP1 PUSH2 0x1197 JUMP JUMPDEST DUP6 MSTORE POP POP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH2 0x180 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP1 NOT AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x4CE DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x12F0 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1303 PUSH2 0x12FE DUP3 PUSH2 0x1EF8 JUMP JUMPDEST PUSH2 0x1ED1 JUMP JUMPDEST DUP2 DUP2 MSTORE SWAP2 POP PUSH1 0x20 DUP1 DUP4 ADD SWAP1 DUP5 ADD PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1340 JUMPI PUSH2 0x132B DUP8 PUSH1 0x20 DUP5 CALLDATALOAD DUP10 ADD ADD PUSH2 0x134A JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 SWAP3 DUP4 ADD SWAP3 SWAP2 SWAP1 SWAP2 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1313 JUMP JUMPDEST POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x135A JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1368 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x137F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x13A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH2 0x13B7 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x13CE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x13DF DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x13F9 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x1402 DUP2 PUSH2 0x1ED1 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x140F DUP4 DUP4 PUSH2 0x12D5 JUMP JUMPDEST DUP2 MSTORE PUSH2 0x141E DUP4 PUSH1 0x20 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH2 0x1430 DUP4 PUSH1 0x40 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD MSTORE PUSH2 0x1442 DUP4 PUSH1 0x60 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP3 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP3 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP3 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x14A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x14B0 DUP7 DUP4 DUP8 ADD PUSH2 0x1398 JUMP JUMPDEST DUP4 DUP6 ADD MSTORE PUSH2 0x160 SWAP3 POP DUP3 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x14CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x14D9 DUP6 DUP3 DUP7 ADD PUSH2 0x1398 JUMP JUMPDEST DUP3 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x14F6 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x1500 PUSH1 0x60 PUSH2 0x1ED1 JUMP JUMPDEST SWAP1 POP DUP2 CALLDATALOAD DUP2 MSTORE PUSH1 0x20 DUP3 ADD CALLDATALOAD PUSH2 0x1514 DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1533 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x153F DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x155D JUMPI DUP2 DUP3 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1573 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP1 DUP5 ADD DUP6 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1584 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 MLOAD SWAP2 POP PUSH2 0x1594 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP4 DUP2 ADD SWAP1 DUP3 DUP6 ADD DUP7 JUMPDEST DUP6 DUP2 LT ISZERO PUSH2 0x15C9 JUMPI PUSH2 0x15B7 DUP11 DUP9 DUP5 MLOAD DUP9 ADD ADD PUSH2 0x13E6 JUMP JUMPDEST DUP5 MSTORE SWAP3 DUP7 ADD SWAP3 SWAP1 DUP7 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x15A0 JUMP JUMPDEST POP SWAP1 SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x15EA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 CALLDATALOAD SWAP2 POP PUSH1 0x20 DUP4 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1608 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x134A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x1630 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1647 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x166C JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x1683 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x80 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x1695 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x169F PUSH1 0x80 PUSH2 0x1ED1 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD PUSH2 0x16AC DUP2 PUSH2 0x1F8C JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 DUP2 DUP2 ADD CALLDATALOAD SWAP1 DUP5 ADD MSTORE PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x16C9 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x16D5 DUP8 DUP3 DUP5 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP PUSH1 0x60 SWAP1 DUP2 ADD CALLDATALOAD SWAP1 DUP4 ADD MSTORE POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x16FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1716 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x1735 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x174D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1759 DUP7 DUP4 DUP8 ADD PUSH2 0x13E6 JUMP JUMPDEST SWAP4 POP PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x176F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x178E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x17A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x14E5 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x17C8 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x17DF JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x17EB DUP10 DUP4 DUP11 ADD PUSH2 0x14E5 JUMP JUMPDEST SWAP7 POP PUSH1 0x20 SWAP2 POP DUP2 DUP9 ADD CALLDATALOAD PUSH2 0x17FE DUP2 PUSH2 0x1F8C JUMP JUMPDEST SWAP6 POP PUSH1 0x40 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1811 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x181D DUP11 DUP3 DUP12 ADD PUSH2 0x134A JUMP JUMPDEST SWAP6 POP POP PUSH1 0x60 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1831 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 DUP10 ADD DUP11 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1842 JUMPI DUP5 DUP6 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP2 POP PUSH2 0x1852 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP5 DUP2 ADD SWAP1 DUP3 DUP7 ADD DUP7 DUP6 MUL DUP5 ADD DUP8 ADD DUP15 LT ISZERO PUSH2 0x186E JUMPI DUP8 DUP9 REVERT JUMPDEST DUP8 SWAP4 POP JUMPDEST DUP5 DUP5 LT ISZERO PUSH2 0x1890 JUMPI DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x1 SWAP4 SWAP1 SWAP4 ADD SWAP3 SWAP2 DUP7 ADD SWAP2 DUP7 ADD PUSH2 0x1872 JUMP JUMPDEST POP SWAP7 POP POP POP POP PUSH1 0x80 DUP9 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x18A9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x18B6 DUP9 DUP3 DUP10 ADD PUSH2 0x12E0 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 POP SWAP3 SWAP6 SWAP1 SWAP4 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 MSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x18F5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE PUSH1 0x1C DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x3C ADD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x1AA0 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE DUP2 MLOAD PUSH2 0x180 PUSH2 0x19DE DUP8 DUP4 MLOAD PUSH2 0x18C3 JUMP JUMPDEST DUP8 DUP3 ADD MLOAD PUSH2 0x19EE DUP10 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0x1A01 PUSH1 0x40 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0x1A14 PUSH1 0x60 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP9 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP9 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP9 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP9 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD DUP3 DUP3 DUP11 ADD MSTORE PUSH2 0x1A6D DUP4 DUP11 ADD DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 SWAP2 POP DUP2 DUP4 ADD MLOAD DUP9 DUP3 SUB DUP4 DUP11 ADD MSTORE PUSH2 0x1A8A DUP3 DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP9 POP POP POP SWAP5 DUP8 ADD SWAP5 POP POP SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x199F JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x12 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F36355F52455155495245440000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F415050524F56414C5F5349474E4154555245000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x46524F4D5F4C4553535F5448414E5F544F5F5245515549524544000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1C SWAP1 DUP3 ADD MSTORE PUSH32 0x544F5F4C4553535F5448414E5F4C454E4754485F524551554952454400000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x17 SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F465245455F4D454D4F52595F505452000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x10 SWAP1 DUP3 ADD MSTORE PUSH32 0x415050524F56414C5F4558504952454400000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x26 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x15 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F554E535550504F525445440000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F4F524947494E000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x21 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F5448414E5F5A45524F5F4C454E4754485F52455155495245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x4400000000000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494C4C4547414C000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1E SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F475245415445525F5448414E5F305F52455155495245440000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494E56414C4944000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x25 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F345F4C454E4754485F524551 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5549524544000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F305F5245515549524544000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP6 DUP3 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH1 0x80 PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1EB4 PUSH1 0x80 DUP4 ADD DUP6 PUSH2 0x18DD JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x60 DUP5 ADD MSTORE PUSH2 0x1EC6 DUP2 DUP6 PUSH2 0x18DD JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1EF0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F0F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 SWAP1 DUP2 MUL ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F30 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1F77 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1F5F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1F86 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x1FAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xbc 0xdb 0x4a 0xab RETURNDATACOPY BYTE DIV 0xea 0x5c 0xd6 0xc1 CODESIZE SWAP2 GT AND 0xce 0xac EXTCODEHASH 0xac DUP9 0xde NOT SWAP6 0xc4 0xd3 CALLCODE 0x4f 0xdd EXTCODEHASH TIMESTAMP 0xf 0xb6 PUSH13 0x6578706572696D656E74616CF5 STOP CALLDATACOPY ", - "sourceMap": "838:227:0:-;;;978:85;8:9:-1;5:2;;;30:1;27;20:12;5:2;978:85:0;;;;;;;;;;;;;;;;;;;;;;830:8:8;:35;;-1:-1:-1;;;;;;830:35:8;-1:-1:-1;;;;;830:35:8;;;;;1425:148:10;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2101:30;;;;;;;;;;;;;;;;2163:33;;;;;;;;;;;;;;;2006:238;;;;1415:159;2085:48;;2147:51;;2228:4;;2006:238;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2006:238:10;;;;1996:249;;49:4:-1;1996:249:10;;;;1963:30;:282;1425:148;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2391:27;;;;;;;;;;;;;;;;2450:30;;;;;;;;;;;;;;;-1:-1:-1;2512:8:10;2296:236;;;;1415:159;2375:45;;2434:48;;-1:-1:-1;;;;;2512:8:10;;;;2296:236;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2296:236:10;;;2286:247;;49:4:-1;2286:247:10;;;;2256:27;:277;-1:-1:-1;838:227:0;;146:263:-1;;261:2;249:9;240:7;236:23;232:32;229:2;;;-1:-1;;267:12;229:2;89:6;83:13;-1:-1;;;;;5679:5;5285:54;5654:5;5651:35;5641:2;;-1:-1;;5690:12;5641:2;319:74;223:186;-1:-1;;;223:186;2777:661;505:58;;;3077:2;3068:12;;505:58;;;;3179:12;;;505:58;3290:12;;;505:58;3401:12;;;2968:470;3445:1440;2506:66;2486:87;;872:66;2470:2;2592:12;;852:87;2097:66;958:12;;;2077:87;1281:66;2183:12;;;1261:87;1689:66;1367:12;;;1669:87;1775:11;;;4029:856;;838:227:0;;;;;;" + "object": "0x60806040523480156200001157600080fd5b506040516020806200235b833981018060405262000033919081019062000252565b600080546001600160a01b0319166001600160a01b0383161790556040516200005f906020016200029f565b60408051601f1981840301815282825280516020918201208383018352601784527f30782050726f746f636f6c20436f6f7264696e61746f720000000000000000009382019390935281518083018352600581527f312e302e300000000000000000000000000000000000000000000000000000009082015290516200012d92917f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236917f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9130910162000284565b60408051601f198184030181529082905280516020918201206001556200015591016200029f565b60408051601f1981840301815282825280516020918201208383018352600b84527f30782050726f746f636f6c0000000000000000000000000000000000000000009382019390935281518083018352600181527f32000000000000000000000000000000000000000000000000000000000000009082015260005491516200023093927ff0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61e927fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5926001600160a01b03909216910162000284565b60408051601f1981840301815291905280516020909101206002555062000360565b6000602082840312156200026557600080fd5b81516001600160a01b03811681146200027d57600080fd5b9392505050565b93845260208401929092526040830152606082015260800190565b7f454950373132446f6d61696e280000000000000000000000000000000000000081527f737472696e67206e616d652c0000000000000000000000000000000000000000600d8201527f737472696e672076657273696f6e2c000000000000000000000000000000000060198201527f6164647265737320766572696679696e67436f6e74726163740000000000000060288201527f2900000000000000000000000000000000000000000000000000000000000000604182015260420190565b611feb80620003706000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037" }, "deployedBytecode": { "linkReferences": {}, @@ -308,118 +306,6 @@ } } }, - "sources": { - "src/Coordinator.sol": { - "id": 0 - }, - "src/libs/LibConstants.sol": { - "id": 8 - }, - "src/interfaces/ITransactions.sol": { - "id": 7 - }, - "src/MixinSignatureValidator.sol": { - "id": 3 - }, - "@0x/contracts-utils/contracts/src/LibBytes.sol": { - "id": 21 - }, - "src/mixins/MSignatureValidator.sol": { - "id": 13 - }, - "src/interfaces/ISignatureValidator.sol": { - "id": 6 - }, - "src/MixinCoordinatorApprovalVerifier.sol": { - "id": 1 - }, - "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": { - "id": 18 - }, - "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": { - "id": 19 - }, - "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": { - "id": 17 - }, - "@0x/contracts-utils/contracts/src/LibAddressArray.sol": { - "id": 20 - }, - "src/libs/LibCoordinatorApproval.sol": { - "id": 9 - }, - "src/libs/LibEIP712Domain.sol": { - "id": 10 - }, - "src/libs/LibZeroExTransaction.sol": { - "id": 11 - }, - "src/mixins/MCoordinatorApprovalVerifier.sol": { - "id": 12 - }, - "src/interfaces/ICoordinatorApprovalVerifier.sol": { - "id": 4 - }, - "src/MixinCoordinatorCore.sol": { - "id": 2 - }, - "src/interfaces/ICoordinatorCore.sol": { - "id": 5 - } - }, - "sourceCodes": { - "src/Coordinator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibConstants.sol\";\nimport \"./MixinSignatureValidator.sol\";\nimport \"./MixinCoordinatorApprovalVerifier.sol\";\nimport \"./MixinCoordinatorCore.sol\";\n\n\n// solhint-disable no-empty-blocks\ncontract Coordinator is\n LibConstants,\n MixinSignatureValidator,\n MixinCoordinatorApprovalVerifier,\n MixinCoordinatorCore\n{\n constructor (address _exchange)\n public\n LibConstants(_exchange)\n {}\n}\n", - "src/libs/LibConstants.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ITransactions.sol\";\n\n\ncontract LibConstants {\n\n // solhint-disable-next-line var-name-mixedcase\n ITransactions internal EXCHANGE;\n\n constructor (address _exchange)\n public\n {\n EXCHANGE = ITransactions(_exchange);\n }\n}\n", - "src/interfaces/ITransactions.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\npragma solidity ^0.5.5;\n\n\ncontract ITransactions {\n\n /// @dev Executes an exchange method call in the context of signer.\n /// @param salt Arbitrary number to ensure uniqueness of transaction hash.\n /// @param signerAddress Address of transaction signer.\n /// @param data AbiV2 encoded calldata.\n /// @param signature Proof of signer transaction by signer.\n function executeTransaction(\n uint256 salt,\n address signerAddress,\n bytes calldata data,\n bytes calldata signature\n )\n external;\n}\n", - "src/MixinSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\n\n\ncontract MixinSignatureValidator is\n MSignatureValidator\n{\n using LibBytes for bytes;\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress)\n {\n require(\n signature.length > 0,\n \"LENGTH_GREATER_THAN_0_REQUIRED\"\n );\n\n // Pop last byte off of signature byte array.\n uint8 signatureTypeRaw = uint8(signature.popLastByte());\n\n // Ensure signature is supported\n require(\n signatureTypeRaw < uint8(SignatureType.NSignatureTypes),\n \"SIGNATURE_UNSUPPORTED\"\n );\n\n SignatureType signatureType = SignatureType(signatureTypeRaw);\n\n // Always illegal signature.\n // This is always an implicit option since a signer can create a\n // signature array with invalid type or length. We may as well make\n // it an explicit option. This aids testing and analysis. It is\n // also the initialization value for the enum type.\n if (signatureType == SignatureType.Illegal) {\n revert(\"SIGNATURE_ILLEGAL\");\n\n // Always invalid signature.\n // Like Illegal, this is always implicitly available and therefore\n // offered explicitly. It can be implicitly created by providing\n // a correctly formatted but incorrect signature.\n } else if (signatureType == SignatureType.Invalid) {\n require(\n signature.length == 0,\n \"LENGTH_0_REQUIRED\"\n );\n revert(\"SIGNATURE_INVALID\");\n\n // Signature using EIP712\n } else if (signatureType == SignatureType.EIP712) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n hash,\n v,\n r,\n s\n );\n return signerAddress;\n\n // Signed using web3.eth_sign\n } else if (signatureType == SignatureType.EthSign) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n keccak256(abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n32\",\n hash\n )),\n v,\n r,\n s\n );\n return signerAddress;\n }\n\n // Anything else is illegal (We do not return false because\n // the signature may actually be valid, just not in a format\n // that we currently support. In this case returning false\n // may lead the caller to incorrectly believe that the\n // signature was invalid.)\n revert(\"SIGNATURE_UNSUPPORTED\");\n }\n}\n", - "@0x/contracts-utils/contracts/src/LibBytes.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\nlibrary LibBytes {\n\n using LibBytes for bytes;\n\n /// @dev Gets the memory address for a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of byte array. This\n /// points to the header of the byte array which contains\n /// the length.\n function rawAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := input\n }\n return memoryAddress;\n }\n \n /// @dev Gets the memory address for the contents of a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of the contents of the byte array.\n function contentAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := add(input, 32)\n }\n return memoryAddress;\n }\n\n /// @dev Copies `length` bytes from memory location `source` to `dest`.\n /// @param dest memory address to copy bytes to.\n /// @param source memory address to copy bytes from.\n /// @param length number of bytes to copy.\n function memCopy(\n uint256 dest,\n uint256 source,\n uint256 length\n )\n internal\n pure\n {\n if (length < 32) {\n // Handle a partial word by reading destination and masking\n // off the bits we are interested in.\n // This correctly handles overlap, zero lengths and source == dest\n assembly {\n let mask := sub(exp(256, sub(32, length)), 1)\n let s := and(mload(source), not(mask))\n let d := and(mload(dest), mask)\n mstore(dest, or(s, d))\n }\n } else {\n // Skip the O(length) loop when source == dest.\n if (source == dest) {\n return;\n }\n\n // For large copies we copy whole words at a time. The final\n // word is aligned to the end of the range (instead of after the\n // previous) to handle partial words. So a copy will look like this:\n //\n // ####\n // ####\n // ####\n // ####\n //\n // We handle overlap in the source and destination range by\n // changing the copying direction. This prevents us from\n // overwriting parts of source that we still need to copy.\n //\n // This correctly handles source == dest\n //\n if (source > dest) {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because it\n // is easier to compare with in the loop, and these\n // are also the addresses we need for copying the\n // last bytes.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the last 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the last bytes in\n // source already due to overlap.\n let last := mload(sEnd)\n\n // Copy whole words front to back\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} lt(source, sEnd) {} {\n mstore(dest, mload(source))\n source := add(source, 32)\n dest := add(dest, 32)\n }\n \n // Write the last 32 bytes\n mstore(dEnd, last)\n }\n } else {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because those\n // are the starting points when copying a word at the end.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the first 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the first bytes in\n // source already due to overlap.\n let first := mload(source)\n\n // Copy whole words back to front\n // We use a signed comparisson here to allow dEnd to become\n // negative (happens when source and dest < 32). Valid\n // addresses in local memory will never be larger than\n // 2**255, so they can be safely re-interpreted as signed.\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} slt(dest, dEnd) {} {\n mstore(dEnd, mload(sEnd))\n sEnd := sub(sEnd, 32)\n dEnd := sub(dEnd, 32)\n }\n \n // Write the first 32 bytes\n mstore(dest, first)\n }\n }\n }\n }\n\n /// @dev Returns a slices from a byte array.\n /// @param b The byte array to take a slice from.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n function slice(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure and copy contents\n result = new bytes(to - from);\n memCopy(\n result.contentAddress(),\n b.contentAddress() + from,\n result.length\n );\n return result;\n }\n \n /// @dev Returns a slice from a byte array without preserving the input.\n /// @param b The byte array to take a slice from. Will be destroyed in the process.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted.\n function sliceDestructive(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure around [from, to) in-place.\n assembly {\n result := add(b, from)\n mstore(result, sub(to, from))\n }\n return result;\n }\n\n /// @dev Pops the last byte off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The byte that was popped off.\n function popLastByte(bytes memory b)\n internal\n pure\n returns (bytes1 result)\n {\n require(\n b.length > 0,\n \"GREATER_THAN_ZERO_LENGTH_REQUIRED\"\n );\n\n // Store last byte.\n result = b[b.length - 1];\n\n assembly {\n // Decrement length of byte array.\n let newLen := sub(mload(b), 1)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Pops the last 20 bytes off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The 20 byte address that was popped off.\n function popLast20Bytes(bytes memory b)\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= 20,\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Store last 20 bytes.\n result = readAddress(b, b.length - 20);\n\n assembly {\n // Subtract 20 from byte array length.\n let newLen := sub(mload(b), 20)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Tests equality of two byte arrays.\n /// @param lhs First byte array to compare.\n /// @param rhs Second byte array to compare.\n /// @return True if arrays are the same. False otherwise.\n function equals(\n bytes memory lhs,\n bytes memory rhs\n )\n internal\n pure\n returns (bool equal)\n {\n // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare.\n // We early exit on unequal lengths, but keccak would also correctly\n // handle this.\n return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs);\n }\n\n /// @dev Reads an address from a position in a byte array.\n /// @param b Byte array containing an address.\n /// @param index Index in byte array of address.\n /// @return address from byte array.\n function readAddress(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Read address from array memory\n assembly {\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 20-byte mask to obtain address\n result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n return result;\n }\n\n /// @dev Writes an address into a specific position in a byte array.\n /// @param b Byte array to insert address into.\n /// @param index Index in byte array of address.\n /// @param input Address to put into byte array.\n function writeAddress(\n bytes memory b,\n uint256 index,\n address input\n )\n internal\n pure\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Store address into array memory\n assembly {\n // The address occupies 20 bytes and mstore stores 32 bytes.\n // First fetch the 32-byte word where we'll be storing the address, then\n // apply a mask so we have only the bytes in the word that the address will not occupy.\n // Then combine these bytes with the address and store the 32 bytes back to memory with mstore.\n\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address\n let neighbors := and(\n mload(add(b, index)),\n 0xffffffffffffffffffffffff0000000000000000000000000000000000000000\n )\n \n // Make sure input address is clean.\n // (Solidity does not guarantee this)\n input := and(input, 0xffffffffffffffffffffffffffffffffffffffff)\n\n // Store the neighbors and address into memory\n mstore(add(b, index), xor(input, neighbors))\n }\n }\n\n /// @dev Reads a bytes32 value from a position in a byte array.\n /// @param b Byte array containing a bytes32 value.\n /// @param index Index in byte array of bytes32 value.\n /// @return bytes32 value from byte array.\n function readBytes32(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes32 result)\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n result := mload(add(b, index))\n }\n return result;\n }\n\n /// @dev Writes a bytes32 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes32 to put into byte array.\n function writeBytes32(\n bytes memory b,\n uint256 index,\n bytes32 input\n )\n internal\n pure\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n mstore(add(b, index), input)\n }\n }\n\n /// @dev Reads a uint256 value from a position in a byte array.\n /// @param b Byte array containing a uint256 value.\n /// @param index Index in byte array of uint256 value.\n /// @return uint256 value from byte array.\n function readUint256(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (uint256 result)\n {\n result = uint256(readBytes32(b, index));\n return result;\n }\n\n /// @dev Writes a uint256 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input uint256 to put into byte array.\n function writeUint256(\n bytes memory b,\n uint256 index,\n uint256 input\n )\n internal\n pure\n {\n writeBytes32(b, index, bytes32(input));\n }\n\n /// @dev Reads an unpadded bytes4 value from a position in a byte array.\n /// @param b Byte array containing a bytes4 value.\n /// @param index Index in byte array of bytes4 value.\n /// @return bytes4 value from byte array.\n function readBytes4(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes4 result)\n {\n require(\n b.length >= index + 4,\n \"GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 32 byte length field\n index += 32;\n\n // Read the bytes4 from array memory\n assembly {\n result := mload(add(b, index))\n // Solidity does not require us to clean the trailing bytes.\n // We do it anyway\n result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)\n }\n return result;\n }\n\n /// @dev Reads nested bytes from a specific position.\n /// @dev NOTE: the returned value overlaps with the input value.\n /// Both should be treated as immutable.\n /// @param b Byte array containing nested bytes.\n /// @param index Index of nested bytes.\n /// @return result Nested bytes.\n function readBytesWithLength(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes memory result)\n {\n // Read length of nested bytes\n uint256 nestedBytesLength = readUint256(b, index);\n index += 32;\n\n // Assert length of is valid, given\n // length of nested bytes\n require(\n b.length >= index + nestedBytesLength,\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n \n // Return a pointer to the byte array as it exists inside `b`\n assembly {\n result := add(b, index)\n }\n return result;\n }\n\n /// @dev Inserts bytes at a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes to insert.\n function writeBytesWithLength(\n bytes memory b,\n uint256 index,\n bytes memory input\n )\n internal\n pure\n {\n // Assert length of is valid, given\n // length of input\n require(\n b.length >= index + 32 + input.length, // 32 bytes to store length\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n\n // Copy into \n memCopy(\n b.contentAddress() + index,\n input.rawAddress(), // includes length of \n input.length + 32 // +32 bytes to store length\n );\n }\n\n /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.\n /// @param dest Byte array that will be overwritten with source bytes.\n /// @param source Byte array to copy onto dest bytes.\n function deepCopyBytes(\n bytes memory dest,\n bytes memory source\n )\n internal\n pure\n {\n uint256 sourceLen = source.length;\n // Dest length must be >= source length, or some bytes would not be copied.\n require(\n dest.length >= sourceLen,\n \"GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED\"\n );\n memCopy(\n dest.contentAddress(),\n source.contentAddress(),\n sourceLen\n );\n }\n}\n", - "src/mixins/MSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ISignatureValidator.sol\";\n\n\ncontract MSignatureValidator is\n ISignatureValidator\n{\n // Allowed signature types.\n enum SignatureType {\n Illegal, // 0x00, default value\n Invalid, // 0x01\n EIP712, // 0x02\n EthSign, // 0x03\n NSignatureTypes // 0x04, number of signature types. Always leave at end.\n }\n}\n", - "src/interfaces/ISignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract ISignatureValidator {\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress);\n}\n", - "src/MixinCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol\";\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibAddressArray.sol\";\nimport \"./libs/LibCoordinatorApproval.sol\";\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\n\n\n// solhint-disable avoid-tx-origin\ncontract MixinCoordinatorApprovalVerifier is\n LibExchangeSelectors,\n LibCoordinatorApproval,\n LibZeroExTransaction,\n MSignatureValidator,\n MCoordinatorApprovalVerifier\n{\n using LibBytes for bytes;\n using LibAddressArray for address[];\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view\n {\n // Get the orders from the the Exchange calldata in the 0x transaction\n LibOrder.Order[] memory orders = decodeOrdersFromFillData(transaction.data);\n\n // No approval is required for non-fill methods\n if (orders.length > 0) {\n // Revert if approval is invalid for transaction orders\n assertValidTransactionOrdersApproval(\n transaction,\n orders,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n }\n }\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders)\n {\n bytes4 selector = data.readBytes4(0);\n if (\n selector == FILL_ORDER_SELECTOR ||\n selector == FILL_ORDER_NO_THROW_SELECTOR ||\n selector == FILL_OR_KILL_ORDER_SELECTOR\n ) {\n // Decode single order\n (LibOrder.Order memory order) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order)\n );\n orders = new LibOrder.Order[](1);\n orders[0] = order;\n } else if (\n selector == BATCH_FILL_ORDERS_SELECTOR ||\n selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||\n selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||\n selector == MARKET_SELL_ORDERS_SELECTOR ||\n selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR\n ) {\n // Decode all orders\n // solhint-disable indent\n (orders) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order[])\n );\n } else if (selector == MATCH_ORDERS_SELECTOR) {\n // Decode left and right orders\n (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order, LibOrder.Order)\n );\n\n // Create array of orders\n orders = new LibOrder.Order[](2);\n orders[0] = leftOrder;\n orders[1] = rightOrder;\n }\n return orders;\n }\n\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view\n {\n // Verify that Ethereum tx signer is the same as the approved txOrigin\n require(\n tx.origin == txOrigin,\n \"INVALID_ORIGIN\"\n );\n\n // Hash 0x transaction\n bytes32 transactionHash = getTransactionHash(transaction);\n\n // Create empty list of approval signers\n address[] memory approvalSignerAddresses = new address[](0);\n\n uint256 signaturesLength = approvalSignatures.length;\n for (uint256 i = 0; i != signaturesLength; i++) {\n // Create approval message\n uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i];\n CoordinatorApproval memory approval = CoordinatorApproval({\n txOrigin: txOrigin,\n transactionHash: transactionHash,\n transactionSignature: transactionSignature,\n approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds\n });\n\n // Ensure approval has not expired\n require(\n // solhint-disable-next-line not-rely-on-time\n currentApprovalExpirationTimeSeconds > block.timestamp,\n \"APPROVAL_EXPIRED\"\n );\n\n // Hash approval message and recover signer address\n bytes32 approvalHash = getCoordinatorApprovalHash(approval);\n address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]);\n\n // Add approval signer to list of signers\n approvalSignerAddresses = approvalSignerAddresses.append(approvalSignerAddress);\n }\n\n // Ethereum transaction signer gives implicit signature of approval\n approvalSignerAddresses = approvalSignerAddresses.append(tx.origin);\n\n uint256 ordersLength = orders.length;\n for (uint256 i = 0; i != ordersLength; i++) {\n // Do not check approval if the order's senderAddress is null\n if (orders[i].senderAddress == address(0)) {\n continue;\n }\n\n // Ensure feeRecipient of order has approved this 0x transaction\n address approverAddress = orders[i].feeRecipientAddress;\n bool isOrderApproved = approvalSignerAddresses.contains(approverAddress);\n require(\n isOrderApproved,\n \"INVALID_APPROVAL_SIGNATURE\"\n );\n }\n }\n}\n", - "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibExchangeSelectors {\n\n // solhint-disable max-line-length\n // allowedValidators\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514;\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256(\"allowedValidators(address,address)\"));\n\n // assetProxies\n bytes4 constant internal ASSET_PROXIES_SELECTOR = 0x3fd3c997;\n bytes4 constant internal ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256(\"assetProxies(bytes4)\"));\n\n // batchCancelOrders\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782;\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // batchFillOrKillOrders\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546;\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrders\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b;\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrdersNoThrow\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190;\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // cancelOrder\n bytes4 constant internal CANCEL_ORDER_SELECTOR = 0xd46b02c3;\n bytes4 constant internal CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // cancelOrdersUpTo\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1;\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrdersUpTo(uint256)\"));\n\n // cancelled\n bytes4 constant internal CANCELLED_SELECTOR = 0x2ac12622;\n bytes4 constant internal CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelled(bytes32)\"));\n\n // currentContextAddress\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba;\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256(\"currentContextAddress()\"));\n\n // executeTransaction\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce;\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256(\"executeTransaction(uint256,address,bytes,bytes)\"));\n\n // fillOrKillOrder\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15;\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrder\n bytes4 constant internal FILL_ORDER_SELECTOR = 0xb4be83d5;\n bytes4 constant internal FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrderNoThrow\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae;\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // filled\n bytes4 constant internal FILLED_SELECTOR = 0x288cdc91;\n bytes4 constant internal FILLED_SELECTOR_GENERATOR = bytes4(keccak256(\"filled(bytes32)\"));\n\n // getAssetProxy\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR = 0x60704108;\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"getAssetProxy(bytes4)\"));\n\n // getOrderInfo\n bytes4 constant internal GET_ORDER_INFO_SELECTOR = 0xc75e0a81;\n bytes4 constant internal GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // getOrdersInfo\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc;\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // isValidSignature\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR = 0x93634702;\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256(\"isValidSignature(bytes32,address,bytes)\"));\n\n // marketBuyOrders\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b;\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketBuyOrdersNoThrow\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380;\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrders\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808;\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrdersNoThrow\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18;\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // matchOrders\n bytes4 constant internal MATCH_ORDERS_SELECTOR = 0x3c28d861;\n bytes4 constant internal MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)\"));\n\n // orderEpoch\n bytes4 constant internal ORDER_EPOCH_SELECTOR = 0xd9bfa73e;\n bytes4 constant internal ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256(\"orderEpoch(address,address)\"));\n\n // owner\n bytes4 constant internal OWNER_SELECTOR = 0x8da5cb5b;\n bytes4 constant internal OWNER_SELECTOR_GENERATOR = bytes4(keccak256(\"owner()\"));\n\n // preSign\n bytes4 constant internal PRE_SIGN_SELECTOR = 0x3683ef8e;\n bytes4 constant internal PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256(\"preSign(bytes32,address,bytes)\"));\n\n // preSigned\n bytes4 constant internal PRE_SIGNED_SELECTOR = 0x82c174d0;\n bytes4 constant internal PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256(\"preSigned(bytes32,address)\"));\n\n // registerAssetProxy\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93;\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"registerAssetProxy(address)\"));\n\n // setSignatureValidatorApproval\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68;\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256(\"setSignatureValidatorApproval(address,bool)\"));\n\n // transactions\n bytes4 constant internal TRANSACTIONS_SELECTOR = 0x642f2eaf;\n bytes4 constant internal TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256(\"transactions(bytes32)\"));\n\n // transferOwnership\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256(\"transferOwnership(address)\"));\n}", - "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibEIP712.sol\";\n\n\ncontract LibOrder is\n LibEIP712\n{\n // Hash for the EIP712 Order Schema\n bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"Order(\",\n \"address makerAddress,\",\n \"address takerAddress,\",\n \"address feeRecipientAddress,\",\n \"address senderAddress,\",\n \"uint256 makerAssetAmount,\",\n \"uint256 takerAssetAmount,\",\n \"uint256 makerFee,\",\n \"uint256 takerFee,\",\n \"uint256 expirationTimeSeconds,\",\n \"uint256 salt,\",\n \"bytes makerAssetData,\",\n \"bytes takerAssetData\",\n \")\"\n ));\n\n // A valid order remains fillable until it is expired, fully filled, or cancelled.\n // An order's state is unaffected by external factors, like account balances.\n enum OrderStatus {\n INVALID, // Default value\n INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount\n INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount\n FILLABLE, // Order is fillable\n EXPIRED, // Order has already expired\n FULLY_FILLED, // Order is fully filled\n CANCELLED // Order has been cancelled\n }\n\n // solhint-disable max-line-length\n struct Order {\n address makerAddress; // Address that created the order. \n address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order. \n address feeRecipientAddress; // Address that will recieve fees when order is filled. \n address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.\n uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0. \n uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0. \n uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.\n uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.\n uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires. \n uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash. \n bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.\n bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.\n }\n // solhint-enable max-line-length\n\n struct OrderInfo {\n uint8 orderStatus; // Status that describes order's validity and fillability.\n bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash).\n uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.\n }\n\n /// @dev Calculates Keccak-256 hash of the order.\n /// @param order The order structure.\n /// @return Keccak-256 EIP712 hash of the order.\n function getOrderHash(Order memory order)\n internal\n view\n returns (bytes32 orderHash)\n {\n orderHash = hashEIP712Message(hashOrder(order));\n return orderHash;\n }\n\n /// @dev Calculates EIP712 hash of the order.\n /// @param order The order structure.\n /// @return EIP712 hash of the order.\n function hashOrder(Order memory order)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;\n bytes32 makerAssetDataHash = keccak256(order.makerAssetData);\n bytes32 takerAssetDataHash = keccak256(order.takerAssetData);\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ORDER_SCHEMA_HASH,\n // bytes32(order.makerAddress),\n // bytes32(order.takerAddress),\n // bytes32(order.feeRecipientAddress),\n // bytes32(order.senderAddress),\n // order.makerAssetAmount,\n // order.takerAssetAmount,\n // order.makerFee,\n // order.takerFee,\n // order.expirationTimeSeconds,\n // order.salt,\n // keccak256(order.makerAssetData),\n // keccak256(order.takerAssetData)\n // ));\n\n assembly {\n // Calculate memory addresses that will be swapped out before hashing\n let pos1 := sub(order, 32)\n let pos2 := add(order, 320)\n let pos3 := add(order, 352)\n\n // Backup\n let temp1 := mload(pos1)\n let temp2 := mload(pos2)\n let temp3 := mload(pos3)\n \n // Hash in place\n mstore(pos1, schemaHash)\n mstore(pos2, makerAssetDataHash)\n mstore(pos3, takerAssetDataHash)\n result := keccak256(pos1, 416)\n \n // Restore\n mstore(pos1, temp1)\n mstore(pos2, temp2)\n mstore(pos3, temp3)\n }\n return result;\n }\n}\n", - "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibEIP712 {\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value\n string constant internal EIP712_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value\n string constant internal EIP712_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_DOMAIN_NAME)),\n keccak256(bytes(EIP712_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712Message(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;\n\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct \n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", - "@0x/contracts-utils/contracts/src/LibAddressArray.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibBytes.sol\";\n\n\nlibrary LibAddressArray {\n\n /// @dev Append a new address to an array of addresses.\n /// The `addressArray` may need to be reallocated to make space\n /// for the new address. Because of this we return the resulting\n /// memory location of `addressArray`.\n /// @param addressArray Array of addresses.\n /// @param addressToAppend Address to append.\n /// @return Array of addresses: [... addressArray, addressToAppend]\n function append(address[] memory addressArray, address addressToAppend)\n internal\n pure\n returns (address[] memory)\n {\n // Get stats on address array and free memory\n uint256 freeMemPtr = 0;\n uint256 addressArrayBeginPtr = 0;\n uint256 addressArrayEndPtr = 0;\n uint256 addressArrayLength = addressArray.length;\n uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);\n assembly {\n freeMemPtr := mload(0x40)\n addressArrayBeginPtr := addressArray\n addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)\n }\n\n // Cases for `freeMemPtr`:\n // `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`\n // `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`\n // `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.\n require(\n freeMemPtr >= addressArrayEndPtr,\n \"INVALID_FREE_MEMORY_PTR\"\n );\n\n // If free memory begins at the end of `addressArray`\n // then we can append `addressToAppend` directly.\n // Otherwise, we must copy the array to free memory\n // before appending new values to it.\n if (freeMemPtr > addressArrayEndPtr) {\n LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);\n assembly {\n addressArray := freeMemPtr\n addressArrayBeginPtr := addressArray\n }\n }\n\n // Append `addressToAppend`\n addressArrayLength += 1;\n addressArrayMemSizeInBytes += 32;\n addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;\n freeMemPtr = addressArrayEndPtr;\n assembly {\n // Store new array length\n mstore(addressArray, addressArrayLength)\n\n // Update `freeMemPtr`\n mstore(0x40, freeMemPtr)\n }\n addressArray[addressArrayLength - 1] = addressToAppend;\n return addressArray;\n }\n\n /// @dev Checks if an address array contains the target address.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return True if the addressArray contains the target.\n function contains(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success to true\n success := 1\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return success;\n }\n\n /// @dev Finds the index of an address within an array.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return Existence and index of the target in the array.\n function indexOf(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success, uint256 index)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success and index\n success := 1\n index := div(sub(i, arrayContentsStart), 32)\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return (success, index);\n }\n}\n", - "src/libs/LibCoordinatorApproval.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibCoordinatorApproval is\n LibEIP712Domain\n{\n // Hash for the EIP712 Coordinator approval message\n // keccak256(abi.encodePacked(\n // \"CoordinatorApproval(\",\n // \"address txOrigin,\",\n // \"bytes32 transactionHash,\",\n // \"bytes transactionSignature,\",\n // \"uint256 approvalExpirationTimeSeconds\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05;\n\n struct CoordinatorApproval {\n address txOrigin; // Required signer of Ethereum transaction that is submitting approval.\n bytes32 transactionHash; // EIP712 hash of the transaction.\n bytes transactionSignature; // Signature of the 0x transaction.\n uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the approval expires.\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.\n function getCoordinatorApprovalHash(CoordinatorApproval memory approval)\n public\n view\n returns (bytes32 approvalHash)\n {\n approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval));\n return approvalHash;\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage with no domain separator.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with no domain separator.\n function hashCoordinatorApproval(CoordinatorApproval memory approval)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH;\n bytes memory transactionSignature = approval.transactionSignature;\n address txOrigin = approval.txOrigin;\n bytes32 transactionHash = approval.transactionHash;\n uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH,\n // approval.txOrigin,\n // approval.transactionHash,\n // keccak256(approval.transactionSignature)\n // approval.approvalExpirationTimeSeconds,\n // ));\n\n assembly {\n // Compute hash of transaction signature\n let transactionSignatureHash := keccak256(add(transactionSignature, 32), mload(transactionSignature))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), txOrigin) // txOrigin\n mstore(add(memPtr, 64), transactionHash) // transactionHash\n mstore(add(memPtr, 96), transactionSignatureHash) // transactionSignatureHash\n mstore(add(memPtr, 128), approvalExpirationTimeSeconds) // approvalExpirationTimeSeconds\n // Compute hash\n result := keccak256(memPtr, 160)\n }\n return result;\n }\n}\n", - "src/libs/LibEIP712Domain.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibConstants.sol\";\n\n\ncontract LibEIP712Domain is\n LibConstants\n{\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_NAME = \"0x Protocol Coordinator\";\n\n // EIP712 Domain Version value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = \"1.0.0\";\n\n // EIP712 Domain Name value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data for the Coordinator\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;\n\n // Hash of the EIP712 Domain Separator data for the Exchange\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)),\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n\n EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)),\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)),\n uint256(address(EXCHANGE))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of this contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712CoordinatorMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of the Exchange contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712ExchangeMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.\n /// @param eip712DomainHash Hash of the domain domain separator data.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)\n internal\n pure\n returns (bytes32 result)\n {\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct\n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", - "src/libs/LibZeroExTransaction.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibZeroExTransaction is\n LibEIP712Domain\n{\n // Hash for the EIP712 0x transaction schema\n // keccak256(abi.encodePacked(\n // \"ZeroExTransaction(\",\n // \"uint256 salt,\",\n // \"address signerAddress,\",\n // \"bytes data\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0x213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c;\n\n struct ZeroExTransaction {\n uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash.\n address signerAddress; // Address of transaction signer.\n bytes data; // AbiV2 encoded calldata.\n }\n\n /// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with the domain separator of this contract.\n function getTransactionHash(ZeroExTransaction memory transaction)\n public\n view\n returns (bytes32 transactionHash)\n {\n // Hash the transaction with the domain separator of the Exchange contract.\n transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction));\n return transactionHash;\n }\n\n /// @dev Calculates EIP712 hash of the 0x transaction with no domain separator.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with no domain separator.\n function hashZeroExTransaction(ZeroExTransaction memory transaction)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;\n bytes memory data = transaction.data;\n uint256 salt = transaction.salt;\n address signerAddress = transaction.signerAddress;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,\n // transaction.salt,\n // uint256(transaction.signerAddress),\n // keccak256(transaction.data)\n // ));\n\n assembly {\n // Compute hash of data\n let dataHash := keccak256(add(data, 32), mload(data))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), salt) // salt\n mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress\n mstore(add(memPtr, 96), dataHash) // hash of data\n\n // Compute hash\n result := keccak256(memPtr, 128)\n }\n return result;\n }\n}\n", - "src/mixins/MCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../interfaces/ICoordinatorApprovalVerifier.sol\";\n\n\ncontract MCoordinatorApprovalVerifier is\n ICoordinatorApprovalVerifier\n{\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view;\n}\n", - "src/interfaces/ICoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorApprovalVerifier {\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view;\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders);\n}\n", - "src/MixinCoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./libs/LibConstants.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\nimport \"./interfaces/ICoordinatorCore.sol\";\n\n\ncontract MixinCoordinatorCore is\n LibConstants,\n MCoordinatorApprovalVerifier,\n ICoordinatorCore\n{\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n {\n // Validate that the 0x transaction has been approves by each feeRecipient\n assertValidCoordinatorApprovals(\n transaction,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n\n // Execute the transaction\n EXCHANGE.executeTransaction(\n transaction.salt,\n transaction.signerAddress,\n transaction.data,\n transactionSignature\n );\n }\n}\n", - "src/interfaces/ICoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorCore {\n\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public;\n}\n" - }, "sourceTreeHashHex": "0xcd3a1dbf858b46a5820dab320baad978613f07ec73d35b6cbbde13c2937bbc04", - "compiler": { - "name": "solc", - "version": "soljson-v0.5.8+commit.23d335f2.js", - "settings": { - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { - "yul": true, - "deduplicate": true, - "cse": true, - "constantOptimizer": true - } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - }, - "evmVersion": "constantinople", - "remappings": [ - "@0x/contracts-utils=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-utils", - "@0x/contracts-exchange-libs=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-exchange-libs" - ] - } - }, "networks": {} -} \ No newline at end of file +} From 25fb636490f59340a081e8942ab4d8e1dd2f1ae0 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 18:19:20 -0700 Subject: [PATCH 30/53] tweak package.jsons --- packages/contract-wrappers/package.json | 2 -- packages/pipeline/package.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 96bdbb8cde..7b30781da7 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -81,8 +81,6 @@ "@0x/typescript-typings": "^4.2.2", "@0x/utils": "^4.3.1", "@0x/web3-wrapper": "^6.0.5", - "@types/eth-sig-util": "^2.1.0", - "eth-sig-util": "^2.1.2", "ethereum-types": "^2.1.2", "ethereumjs-abi": "0.6.5", "ethereumjs-blockstream": "6.0.0", diff --git a/packages/pipeline/package.json b/packages/pipeline/package.json index dafa96c795..5e9188588b 100644 --- a/packages/pipeline/package.json +++ b/packages/pipeline/package.json @@ -63,6 +63,6 @@ "ramda": "^0.25.0", "reflect-metadata": "^0.1.12", "sqlite3": "^4.0.2", - "typeorm": "0.2.7" + "typeorm": "^0.2.7" } } From 9f301eefed0511e3f322a043a95211d9a1ee14a8 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 18:32:06 -0700 Subject: [PATCH 31/53] pin pipeline version again --- packages/pipeline/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pipeline/package.json b/packages/pipeline/package.json index 5e9188588b..dafa96c795 100644 --- a/packages/pipeline/package.json +++ b/packages/pipeline/package.json @@ -63,6 +63,6 @@ "ramda": "^0.25.0", "reflect-metadata": "^0.1.12", "sqlite3": "^4.0.2", - "typeorm": "^0.2.7" + "typeorm": "0.2.7" } } From 87ea0d579bb049b10a4d124ad178b07fd4141d0b Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 18:33:27 -0700 Subject: [PATCH 32/53] update Coordinator artifact in python packages --- .../artifacts/Coordinator.json | 118 +----------------- 1 file changed, 2 insertions(+), 116 deletions(-) diff --git a/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json b/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json index c8af051309..d7f985e8d9 100644 --- a/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json +++ b/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/Coordinator.json @@ -296,9 +296,7 @@ "evm": { "bytecode": { "linkReferences": {}, - "object": "0x60806040523480156200001157600080fd5b506040516020806200235b833981018060405262000033919081019062000252565b600080546001600160a01b0319166001600160a01b0383161790556040516200005f906020016200029f565b60408051601f1981840301815282825280516020918201208383018352601784527f30782050726f746f636f6c20436f6f7264696e61746f720000000000000000009382019390935281518083018352600581527f312e302e300000000000000000000000000000000000000000000000000000009082015290516200012d92917f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236917f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9130910162000284565b60408051601f198184030181529082905280516020918201206001556200015591016200029f565b60408051601f1981840301815282825280516020918201208383018352600b84527f30782050726f746f636f6c0000000000000000000000000000000000000000009382019390935281518083018352600181527f32000000000000000000000000000000000000000000000000000000000000009082015260005491516200023093927ff0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61e927fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5926001600160a01b03909216910162000284565b60408051601f1981840301815291905280516020909101206002555062000360565b6000602082840312156200026557600080fd5b81516001600160a01b03811681146200027d57600080fd5b9392505050565b93845260208401929092526040830152606082015260800190565b7f454950373132446f6d61696e280000000000000000000000000000000000000081527f737472696e67206e616d652c0000000000000000000000000000000000000000600d8201527f737472696e672076657273696f6e2c000000000000000000000000000000000060198201527f6164647265737320766572696679696e67436f6e74726163740000000000000060288201527f2900000000000000000000000000000000000000000000000000000000000000604182015260420190565b611feb80620003706000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH3 0x11 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH3 0x235B DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE PUSH3 0x33 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH3 0x252 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP4 AND OR SWAP1 SSTORE PUSH1 0x40 MLOAD PUSH3 0x5F SWAP1 PUSH1 0x20 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0x17 DUP5 MSTORE PUSH32 0x30782050726F746F636F6C20436F6F7264696E61746F72000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x5 DUP2 MSTORE PUSH32 0x312E302E30000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE SWAP1 MLOAD PUSH3 0x12D SWAP3 SWAP2 PUSH32 0x626D101E477FD17DD52AFB3F9AD9EB016BF60F6E377877F34E8F3EA84C930236 SWAP2 PUSH32 0x6C015BD22B4C69690933C1058878EBDFEF31F9AAAE40BBE86D8A09FE1B2972C SWAP2 ADDRESS SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP1 DUP3 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 PUSH1 0x1 SSTORE PUSH3 0x155 SWAP2 ADD PUSH3 0x29F JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE DUP3 DUP3 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP2 DUP3 ADD KECCAK256 DUP4 DUP4 ADD DUP4 MSTORE PUSH1 0xB DUP5 MSTORE PUSH32 0x30782050726F746F636F6C000000000000000000000000000000000000000000 SWAP4 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x1 DUP2 MSTORE PUSH32 0x3200000000000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE PUSH1 0x0 SLOAD SWAP2 MLOAD PUSH3 0x230 SWAP4 SWAP3 PUSH32 0xF0F24618F4C4BE1E62E026FB039A20EF96F4495294817D1027FFAA6D1F70E61E SWAP3 PUSH32 0xAD7C5BEF027816A800DA1736444FB58A807EF4C9603B7848673F7E3A68EB14A5 SWAP3 PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND SWAP2 ADD PUSH3 0x284 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1F NOT DUP2 DUP5 SUB ADD DUP2 MSTORE SWAP2 SWAP1 MSTORE DUP1 MLOAD PUSH1 0x20 SWAP1 SWAP2 ADD KECCAK256 PUSH1 0x2 SSTORE POP PUSH3 0x360 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH3 0x265 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB DUP2 AND DUP2 EQ PUSH3 0x27D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0x20 DUP5 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH32 0x454950373132446F6D61696E2800000000000000000000000000000000000000 DUP2 MSTORE PUSH32 0x737472696E67206E616D652C0000000000000000000000000000000000000000 PUSH1 0xD DUP3 ADD MSTORE PUSH32 0x737472696E672076657273696F6E2C0000000000000000000000000000000000 PUSH1 0x19 DUP3 ADD MSTORE PUSH32 0x6164647265737320766572696679696E67436F6E747261637400000000000000 PUSH1 0x28 DUP3 ADD MSTORE PUSH32 0x2900000000000000000000000000000000000000000000000000000000000000 PUSH1 0x41 DUP3 ADD MSTORE PUSH1 0x42 ADD SWAP1 JUMP JUMPDEST PUSH2 0x1FEB DUP1 PUSH3 0x370 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xC26CFECD GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xC26CFECD EQ PUSH2 0xFE JUMPI DUP1 PUSH4 0xD2DF0733 EQ PUSH2 0x106 JUMPI DUP1 PUSH4 0xEE55B968 EQ PUSH2 0x119 JUMPI DUP1 PUSH4 0xFB6961CC EQ PUSH2 0x139 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0xF7D8E39 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x23872F55 EQ PUSH2 0xB6 JUMPI DUP1 PUSH4 0x48A321D6 EQ PUSH2 0xD6 JUMPI DUP1 PUSH4 0x90C3BC3F EQ PUSH2 0xE9 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA0 PUSH2 0x9B CALLDATASIZE PUSH1 0x4 PUSH2 0x15D7 JUMP JUMPDEST PUSH2 0x141 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1958 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xC9 PUSH2 0xC4 CALLDATASIZE PUSH1 0x4 PUSH2 0x177C JUMP JUMPDEST PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1AAD JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xE4 CALLDATASIZE PUSH1 0x4 PUSH2 0x165B JUMP JUMPDEST PUSH2 0x4E7 JUMP JUMPDEST PUSH2 0xFC PUSH2 0xF7 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x4FA JUMP JUMPDEST STOP JUMPDEST PUSH2 0xC9 PUSH2 0x5A6 JUMP JUMPDEST PUSH2 0xFC PUSH2 0x114 CALLDATASIZE PUSH1 0x4 PUSH2 0x17B1 JUMP JUMPDEST PUSH2 0x5AC JUMP JUMPDEST PUSH2 0x12C PUSH2 0x127 CALLDATASIZE PUSH1 0x4 PUSH2 0x161E JUMP JUMPDEST PUSH2 0x5DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xAD SWAP2 SWAP1 PUSH2 0x1979 JUMP JUMPDEST PUSH2 0xC9 PUSH2 0xA8F JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0x186 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D7D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0x191 DUP4 PUSH2 0xA95 JUMP JUMPDEST PUSH1 0xF8 SHR SWAP1 POP PUSH1 0x4 DUP2 LT PUSH2 0x1D0 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0xFF AND PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1E1 JUMPI INVALID JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x1F1 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x229 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1D46 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x237 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x2A8 JUMPI DUP4 MLOAD ISZERO PUSH2 0x276 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1E48 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DB4 JUMP JUMPDEST PUSH1 0x2 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x2B6 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x3BB JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x2F7 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x306 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x329 DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x33E DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x385 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP7 POP PUSH2 0x4CE SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x3 DUP2 PUSH1 0x4 DUP2 GT ISZERO PUSH2 0x3C9 JUMPI INVALID JUMPDEST EQ ISZERO PUSH2 0x49C JUMPI DUP4 MLOAD PUSH1 0x41 EQ PUSH2 0x40A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1AD4 JUMP JUMPDEST PUSH1 0x0 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x419 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD PUSH1 0xF8 SWAP1 DUP2 SHR DUP2 SHL SWAP1 SHR SWAP1 POP PUSH1 0x0 PUSH2 0x43C DUP7 PUSH1 0x1 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x451 DUP8 PUSH1 0x21 PUSH4 0xFFFFFFFF PUSH2 0xB18 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x1 DUP9 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x466 SWAP2 SWAP1 PUSH2 0x1927 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 DUP5 DUP5 DUP5 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x363 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x1AB6 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C7B JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4E2 DUP4 PUSH2 0xB61 JUMP JUMPDEST PUSH2 0xBCF JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH2 0x4F5 DUP4 PUSH2 0xBDD JUMP JUMPDEST PUSH2 0xC3C JUMP JUMPDEST PUSH2 0x507 DUP6 DUP6 DUP6 DUP6 DUP6 PUSH2 0x5AC JUMP JUMPDEST PUSH1 0x0 SLOAD DUP6 MLOAD PUSH1 0x20 DUP8 ADD MLOAD PUSH1 0x40 DUP1 DUP10 ADD MLOAD SWAP1 MLOAD PUSH32 0xBFC8BFCE00000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP5 AND SWAP4 PUSH4 0xBFC8BFCE SWAP4 PUSH2 0x56D SWAP4 SWAP1 SWAP3 SWAP1 SWAP2 DUP10 SWAP1 PUSH1 0x4 ADD PUSH2 0x1E7F JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x587 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x59B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x60 PUSH2 0x5BB DUP7 PUSH1 0x40 ADD MLOAD PUSH2 0x5DB JUMP JUMPDEST DUP1 MLOAD SWAP1 SWAP2 POP ISZERO PUSH2 0x5D3 JUMPI PUSH2 0x5D3 DUP7 DUP3 DUP8 DUP8 DUP8 DUP8 PUSH2 0xC4A JUMP JUMPDEST POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x0 PUSH2 0x5EF DUP4 DUP3 PUSH4 0xFFFFFFFF PUSH2 0xE98 AND JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xB4BE83D500000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x682 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3E228BAE00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x6CE JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x64A3BC1500000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x757 JUMPI PUSH2 0x6DB PUSH2 0x11DB JUMP JUMPDEST DUP4 MLOAD PUSH2 0x6F1 SWAP1 DUP6 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x704 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x16ED JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x1 DUP1 DUP3 MSTORE DUP2 DUP4 ADD SWAP1 SWAP3 MSTORE SWAP2 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0x723 PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x71B JUMPI SWAP1 POP POP SWAP3 POP DUP1 DUP4 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x746 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x297BB70B00000000000000000000000000000000000000000000000000000000 EQ DUP1 PUSH2 0x7E8 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x50DDE19000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x834 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x4D0AE54600000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x880 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xE5FA431B00000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x8CC JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xA3E2038000000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x918 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x7E1D980800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST DUP1 PUSH2 0x964 JUMPI POP PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0xDD1C7D1800000000000000000000000000000000000000000000000000000000 EQ JUMPDEST ISZERO PUSH2 0x999 JUMPI DUP3 MLOAD PUSH2 0x97F SWAP1 DUP5 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0x992 SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x154B JUMP JUMPDEST SWAP2 POP PUSH2 0xA89 JUMP JUMPDEST PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 DUP2 AND PUSH32 0x3C28D86100000000000000000000000000000000000000000000000000000000 EQ ISZERO PUSH2 0xA89 JUMPI PUSH2 0x9EB PUSH2 0x11DB JUMP JUMPDEST PUSH2 0x9F3 PUSH2 0x11DB JUMP JUMPDEST DUP5 MLOAD PUSH2 0xA09 SWAP1 DUP7 SWAP1 PUSH1 0x4 SWAP1 PUSH4 0xFFFFFFFF PUSH2 0xF03 AND JUMP JUMPDEST DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH2 0xA1C SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH2 0x1722 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 ADD SWAP1 SWAP3 MSTORE SWAP3 SWAP5 POP SWAP1 SWAP3 POP DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0xA3F PUSH2 0x11DB JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0xA37 JUMPI SWAP1 POP POP SWAP4 POP DUP2 DUP5 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0xA62 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP DUP1 DUP5 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0xA7B JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP POP POP JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x1 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP3 MLOAD GT PUSH2 0xAD1 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CE9 JUMP JUMPDEST DUP2 PUSH1 0x1 DUP4 MLOAD SUB DUP2 MLOAD DUP2 LT PUSH2 0xAE1 JUMPI INVALID JUMPDEST ADD PUSH1 0x20 ADD MLOAD DUP3 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ADD SWAP1 SWAP3 MSTORE POP PUSH1 0xF8 SWAP1 DUP2 SHR SWAP1 SHL SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x20 ADD DUP4 MLOAD LT ISZERO PUSH2 0xB58 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1C1E JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP2 DUP2 ADD MLOAD DUP3 MLOAD PUSH1 0x20 SWAP4 DUP5 ADD MLOAD DUP3 MLOAD SWAP3 DUP6 ADD SWAP3 SWAP1 SWAP3 KECCAK256 DUP4 MLOAD PUSH32 0x213C6F636F3EA94E701C0ADF9B2624AA45A6C694F9A292C094F9A81C24B5DF4C DUP2 MSTORE SWAP5 DUP6 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x2 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST PUSH1 0x40 DUP1 DUP3 ADD MLOAD DUP3 MLOAD PUSH1 0x20 DUP1 DUP6 ADD MLOAD PUSH1 0x60 DUP7 DUP2 ADD MLOAD DUP6 MLOAD SWAP6 DUP5 ADD SWAP6 SWAP1 SWAP6 KECCAK256 DUP7 MLOAD PUSH32 0x2FBCDBAA76BC7589916958AE919DFBEF04D23F6BBF26DE6FF317B32C6CC01E05 DUP2 MSTORE SWAP4 DUP5 ADD SWAP5 SWAP1 SWAP5 MSTORE SWAP5 DUP3 ADD MSTORE SWAP3 DUP4 ADD MSTORE PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 SWAP1 KECCAK256 SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4CE PUSH1 0x1 SLOAD DUP4 PUSH2 0xFCF JUMP JUMPDEST ORIGIN PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND EQ PUSH2 0xC99 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1CB2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xCA4 DUP8 PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x0 DUP1 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 SWAP3 MSTORE DUP5 MLOAD SWAP3 SWAP4 POP SWAP2 SWAP1 JUMPDEST DUP2 DUP2 EQ PUSH2 0xDA5 JUMPI PUSH1 0x0 DUP7 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xCD1 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD SWAP1 POP PUSH2 0xCE3 PUSH2 0x1294 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 DUP12 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP8 DUP2 MSTORE PUSH1 0x20 ADD DUP11 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP2 MSTORE POP SWAP1 POP TIMESTAMP DUP3 GT PUSH2 0xD55 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BE7 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xD60 DUP3 PUSH2 0x4E7 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xD81 DUP3 DUP11 DUP8 DUP2 MLOAD DUP2 LT PUSH2 0xD74 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH2 0x141 JUMP JUMPDEST SWAP1 POP PUSH2 0xD93 DUP8 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST SWAP7 POP POP PUSH1 0x1 SWAP1 SWAP4 ADD SWAP3 POP PUSH2 0xCBC SWAP2 POP POP JUMP JUMPDEST POP PUSH2 0xDB6 DUP3 ORIGIN PUSH4 0xFFFFFFFF PUSH2 0x1009 AND JUMP JUMPDEST DUP9 MLOAD SWAP1 SWAP3 POP PUSH1 0x0 JUMPDEST DUP2 DUP2 EQ PUSH2 0xE8B JUMPI PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xDE9 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x60 ADD MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0xE16 JUMPI PUSH2 0xE83 JUMP JUMPDEST PUSH1 0x0 DUP11 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0xE24 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD MLOAD PUSH1 0x40 ADD MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0xE47 DUP3 DUP8 PUSH2 0x10D0 SWAP1 SWAP2 SWAP1 PUSH4 0xFFFFFFFF AND JUMP JUMPDEST SWAP1 POP DUP1 PUSH2 0xE80 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B0B JUMP JUMPDEST POP POP JUMPDEST PUSH1 0x1 ADD PUSH2 0xDBE JUMP JUMPDEST POP POP POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH1 0x4 ADD DUP4 MLOAD LT ISZERO PUSH2 0xED8 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1DEB JUMP JUMPDEST POP ADD PUSH1 0x20 ADD MLOAD PUSH32 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 AND SWAP1 JUMP JUMPDEST PUSH1 0x60 DUP2 DUP4 GT ISZERO PUSH2 0xF3F JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B42 JUMP JUMPDEST DUP4 MLOAD DUP3 GT ISZERO PUSH2 0xF7A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1B79 JUMP JUMPDEST DUP3 DUP3 SUB PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x1F ADD PUSH1 0x1F NOT AND PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0xFA7 JUMPI PUSH1 0x20 DUP3 ADD DUP2 DUP1 CODESIZE DUP4 CODECOPY ADD SWAP1 POP JUMPDEST POP SWAP1 POP PUSH2 0xFC8 PUSH2 0xFB6 DUP3 PUSH2 0x1111 JUMP JUMPDEST DUP5 PUSH2 0xFC0 DUP8 PUSH2 0x1111 JUMP JUMPDEST ADD DUP4 MLOAD PUSH2 0x1117 JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x2 DUP2 ADD SWAP3 SWAP1 SWAP3 MSTORE PUSH1 0x22 DUP3 ADD MSTORE PUSH1 0x42 SWAP1 KECCAK256 SWAP1 JUMP JUMPDEST DUP2 MLOAD PUSH1 0x40 MLOAD PUSH1 0x60 SWAP2 DUP5 SWAP1 PUSH1 0x20 DUP1 DUP3 MUL DUP1 DUP5 ADD DUP3 ADD SWAP3 SWAP2 ADD DUP3 DUP6 LT ISZERO PUSH2 0x105A JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x17D SWAP1 PUSH2 0x1BB0 JUMP JUMPDEST DUP3 DUP6 GT ISZERO PUSH2 0x1074 JUMPI PUSH2 0x106D DUP6 DUP6 DUP4 PUSH2 0x1117 JUMP JUMPDEST DUP5 SWAP8 POP DUP8 SWAP4 POP JUMPDEST PUSH1 0x1 DUP3 ADD SWAP2 POP PUSH1 0x20 DUP2 ADD SWAP1 POP DUP1 DUP5 ADD SWAP3 POP DUP3 SWAP5 POP DUP2 DUP9 MSTORE DUP5 PUSH1 0x40 MSTORE DUP7 DUP9 PUSH1 0x1 DUP5 SUB DUP2 MLOAD DUP2 LT PUSH2 0x109F JUMPI INVALID JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND PUSH1 0x20 SWAP3 DUP4 MUL SWAP2 SWAP1 SWAP2 ADD SWAP1 SWAP2 ADD MSTORE POP SWAP6 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP4 MLOAD MUL PUSH1 0x20 DUP5 ADD DUP2 DUP2 ADD DUP2 SWAP3 POP JUMPDEST DUP1 DUP4 LT ISZERO PUSH2 0x1108 JUMPI DUP3 MLOAD DUP1 DUP7 EQ ISZERO PUSH2 0x10FC JUMPI PUSH1 0x1 SWAP5 POP DUP2 SWAP4 POP JUMPDEST POP PUSH1 0x20 DUP4 ADD SWAP3 POP PUSH2 0x10E2 JUMP JUMPDEST POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1141 JUMPI PUSH1 0x1 DUP2 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP4 MLOAD AND DUP2 DUP6 MLOAD AND DUP1 DUP3 OR DUP7 MSTORE POP POP POP PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 EQ ISZERO PUSH2 0x114E JUMPI PUSH2 0x11D6 JUMP JUMPDEST DUP3 DUP3 GT ISZERO PUSH2 0x1188 JUMPI PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP2 MLOAD JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x1180 JUMPI DUP5 MLOAD DUP7 MSTORE PUSH1 0x20 SWAP6 DUP7 ADD SWAP6 SWAP1 SWAP5 ADD SWAP4 PUSH2 0x1165 JUMP JUMPDEST SWAP1 MSTORE POP PUSH2 0x11D6 JUMP JUMPDEST PUSH1 0x20 DUP2 SUB SWAP1 POP DUP1 DUP3 ADD DUP2 DUP5 ADD DUP4 MLOAD JUMPDEST DUP2 DUP7 SLT ISZERO PUSH2 0x11D1 JUMPI DUP3 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP3 DUP4 ADD SWAP3 SWAP1 SWAP2 ADD SWAP1 PUSH2 0x1197 JUMP JUMPDEST DUP6 MSTORE POP POP JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH2 0x180 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP1 NOT AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST DUP1 MLOAD PUSH2 0x4CE DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x12F0 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1303 PUSH2 0x12FE DUP3 PUSH2 0x1EF8 JUMP JUMPDEST PUSH2 0x1ED1 JUMP JUMPDEST DUP2 DUP2 MSTORE SWAP2 POP PUSH1 0x20 DUP1 DUP4 ADD SWAP1 DUP5 ADD PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1340 JUMPI PUSH2 0x132B DUP8 PUSH1 0x20 DUP5 CALLDATALOAD DUP10 ADD ADD PUSH2 0x134A JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 SWAP3 DUP4 ADD SWAP3 SWAP2 SWAP1 SWAP2 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1313 JUMP JUMPDEST POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x135A JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH2 0x1368 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x137F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x13A9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH2 0x13B7 PUSH2 0x12FE DUP3 PUSH2 0x1F19 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x13CE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x13DF DUP2 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x180 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x13F9 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x1402 DUP2 PUSH2 0x1ED1 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x140F DUP4 DUP4 PUSH2 0x12D5 JUMP JUMPDEST DUP2 MSTORE PUSH2 0x141E DUP4 PUSH1 0x20 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH2 0x1430 DUP4 PUSH1 0x40 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD MSTORE PUSH2 0x1442 DUP4 PUSH1 0x60 DUP5 ADD PUSH2 0x12D5 JUMP JUMPDEST PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP3 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP3 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP3 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP3 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP4 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x14A4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x14B0 DUP7 DUP4 DUP8 ADD PUSH2 0x1398 JUMP JUMPDEST DUP4 DUP6 ADD MSTORE PUSH2 0x160 SWAP3 POP DUP3 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x14CC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x14D9 DUP6 DUP3 DUP7 ADD PUSH2 0x1398 JUMP JUMPDEST DUP3 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x14F6 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x1500 PUSH1 0x60 PUSH2 0x1ED1 JUMP JUMPDEST SWAP1 POP DUP2 CALLDATALOAD DUP2 MSTORE PUSH1 0x20 DUP3 ADD CALLDATALOAD PUSH2 0x1514 DUP2 PUSH2 0x1F8C JUMP JUMPDEST PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x40 DUP3 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1533 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x153F DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MSTORE POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x155D JUMPI DUP2 DUP3 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1573 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP1 DUP5 ADD DUP6 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1584 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 MLOAD SWAP2 POP PUSH2 0x1594 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP4 DUP2 ADD SWAP1 DUP3 DUP6 ADD DUP7 JUMPDEST DUP6 DUP2 LT ISZERO PUSH2 0x15C9 JUMPI PUSH2 0x15B7 DUP11 DUP9 DUP5 MLOAD DUP9 ADD ADD PUSH2 0x13E6 JUMP JUMPDEST DUP5 MSTORE SWAP3 DUP7 ADD SWAP3 SWAP1 DUP7 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x15A0 JUMP JUMPDEST POP SWAP1 SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x15EA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 CALLDATALOAD SWAP2 POP PUSH1 0x20 DUP4 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1608 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x134A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x1630 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1647 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x134A JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x166C JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x1683 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x80 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x1695 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x169F PUSH1 0x80 PUSH2 0x1ED1 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD PUSH2 0x16AC DUP2 PUSH2 0x1F8C JUMP JUMPDEST DUP4 MSTORE PUSH1 0x20 DUP2 DUP2 ADD CALLDATALOAD SWAP1 DUP5 ADD MSTORE PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x16C9 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x16D5 DUP8 DUP3 DUP5 ADD PUSH2 0x134A JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP PUSH1 0x60 SWAP1 DUP2 ADD CALLDATALOAD SWAP1 DUP4 ADD MSTORE POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x16FF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x1716 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x1735 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 MLOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x174D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1759 DUP7 DUP4 DUP8 ADD PUSH2 0x13E6 JUMP JUMPDEST SWAP4 POP PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x176F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x1614 DUP6 DUP3 DUP7 ADD PUSH2 0x13E6 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x178E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x17A5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1653 DUP5 DUP3 DUP6 ADD PUSH2 0x14E5 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x17C8 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x17DF JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x17EB DUP10 DUP4 DUP11 ADD PUSH2 0x14E5 JUMP JUMPDEST SWAP7 POP PUSH1 0x20 SWAP2 POP DUP2 DUP9 ADD CALLDATALOAD PUSH2 0x17FE DUP2 PUSH2 0x1F8C JUMP JUMPDEST SWAP6 POP PUSH1 0x40 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1811 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x181D DUP11 DUP3 DUP12 ADD PUSH2 0x134A JUMP JUMPDEST SWAP6 POP POP PUSH1 0x60 DUP9 ADD CALLDATALOAD DUP2 DUP2 GT ISZERO PUSH2 0x1831 JUMPI DUP4 DUP5 REVERT JUMPDEST DUP1 DUP10 ADD DUP11 PUSH1 0x1F DUP3 ADD SLT PUSH2 0x1842 JUMPI DUP5 DUP6 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP2 POP PUSH2 0x1852 PUSH2 0x12FE DUP4 PUSH2 0x1EF8 JUMP JUMPDEST DUP3 DUP2 MSTORE DUP5 DUP2 ADD SWAP1 DUP3 DUP7 ADD DUP7 DUP6 MUL DUP5 ADD DUP8 ADD DUP15 LT ISZERO PUSH2 0x186E JUMPI DUP8 DUP9 REVERT JUMPDEST DUP8 SWAP4 POP JUMPDEST DUP5 DUP5 LT ISZERO PUSH2 0x1890 JUMPI DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x1 SWAP4 SWAP1 SWAP4 ADD SWAP3 SWAP2 DUP7 ADD SWAP2 DUP7 ADD PUSH2 0x1872 JUMP JUMPDEST POP SWAP7 POP POP POP POP PUSH1 0x80 DUP9 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x18A9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x18B6 DUP9 DUP3 DUP10 ADD PUSH2 0x12E0 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP6 POP SWAP3 SWAP6 SWAP1 SWAP4 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 MSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x18F5 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x1F5C JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE PUSH1 0x1C DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x3C ADD SWAP1 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x1AA0 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE DUP2 MLOAD PUSH2 0x180 PUSH2 0x19DE DUP8 DUP4 MLOAD PUSH2 0x18C3 JUMP JUMPDEST DUP8 DUP3 ADD MLOAD PUSH2 0x19EE DUP10 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x40 DUP3 ADD MLOAD PUSH2 0x1A01 PUSH1 0x40 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x60 DUP3 ADD MLOAD PUSH2 0x1A14 PUSH1 0x60 DUP10 ADD DUP3 PUSH2 0x18C3 JUMP JUMPDEST POP PUSH1 0x80 DUP3 ADD MLOAD PUSH1 0x80 DUP9 ADD MSTORE PUSH1 0xA0 DUP3 ADD MLOAD PUSH1 0xA0 DUP9 ADD MSTORE PUSH1 0xC0 DUP3 ADD MLOAD PUSH1 0xC0 DUP9 ADD MSTORE PUSH1 0xE0 DUP3 ADD MLOAD PUSH1 0xE0 DUP9 ADD MSTORE PUSH2 0x100 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x120 DUP1 DUP4 ADD MLOAD DUP2 DUP10 ADD MSTORE POP PUSH2 0x140 DUP1 DUP4 ADD MLOAD DUP3 DUP3 DUP11 ADD MSTORE PUSH2 0x1A6D DUP4 DUP11 ADD DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP2 POP POP PUSH2 0x160 SWAP2 POP DUP2 DUP4 ADD MLOAD DUP9 DUP3 SUB DUP4 DUP11 ADD MSTORE PUSH2 0x1A8A DUP3 DUP3 PUSH2 0x18DD JUMP JUMPDEST SWAP9 POP POP POP SWAP5 DUP8 ADD SWAP5 POP POP SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x199F JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x12 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F36355F52455155495245440000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F415050524F56414C5F5349474E4154555245000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1A SWAP1 DUP3 ADD MSTORE PUSH32 0x46524F4D5F4C4553535F5448414E5F544F5F5245515549524544000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1C SWAP1 DUP3 ADD MSTORE PUSH32 0x544F5F4C4553535F5448414E5F4C454E4754485F524551554952454400000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x17 SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F465245455F4D454D4F52595F505452000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x10 SWAP1 DUP3 ADD MSTORE PUSH32 0x415050524F56414C5F4558504952454400000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x26 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F33325F4C454E4754485F5245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5155495245440000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x15 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F554E535550504F525445440000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x494E56414C49445F4F524947494E000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x21 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F5448414E5F5A45524F5F4C454E4754485F52455155495245 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x4400000000000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494C4C4547414C000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x1E SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F475245415445525F5448414E5F305F52455155495245440000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x5349474E41545552455F494E56414C4944000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x25 SWAP1 DUP3 ADD MSTORE PUSH32 0x475245415445525F4F525F455155414C5F544F5F345F4C454E4754485F524551 PUSH1 0x40 DUP3 ADD MSTORE PUSH32 0x5549524544000000000000000000000000000000000000000000000000000000 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0x11 SWAP1 DUP3 ADD MSTORE PUSH32 0x4C454E4754485F305F5245515549524544000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP6 DUP3 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH1 0x80 PUSH1 0x40 DUP4 ADD MSTORE PUSH2 0x1EB4 PUSH1 0x80 DUP4 ADD DUP6 PUSH2 0x18DD JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x60 DUP5 ADD MSTORE PUSH2 0x1EC6 DUP2 DUP6 PUSH2 0x18DD JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1EF0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F0F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x20 SWAP1 DUP2 MUL ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH8 0xFFFFFFFFFFFFFFFF DUP3 GT ISZERO PUSH2 0x1F30 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1F77 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1F5F JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1F86 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x1FAE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xbc 0xdb 0x4a 0xab RETURNDATACOPY BYTE DIV 0xea 0x5c 0xd6 0xc1 CODESIZE SWAP2 GT AND 0xce 0xac EXTCODEHASH 0xac DUP9 0xde NOT SWAP6 0xc4 0xd3 CALLCODE 0x4f 0xdd EXTCODEHASH TIMESTAMP 0xf 0xb6 PUSH13 0x6578706572696D656E74616CF5 STOP CALLDATACOPY ", - "sourceMap": "838:227:0:-;;;978:85;8:9:-1;5:2;;;30:1;27;20:12;5:2;978:85:0;;;;;;;;;;;;;;;;;;;;;;830:8:8;:35;;-1:-1:-1;;;;;;830:35:8;-1:-1:-1;;;;;830:35:8;;;;;1425:148:10;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2101:30;;;;;;;;;;;;;;;;2163:33;;;;;;;;;;;;;;;2006:238;;;;1415:159;2085:48;;2147:51;;2228:4;;2006:238;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2006:238:10;;;;1996:249;;49:4:-1;1996:249:10;;;;1963:30;:282;1425:148;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;1425:148:10;;;1415:159;;49:4:-1;1415:159:10;;;;2391:27;;;;;;;;;;;;;;;;2450:30;;;;;;;;;;;;;;;-1:-1:-1;2512:8:10;2296:236;;;;1415:159;2375:45;;2434:48;;-1:-1:-1;;;;;2512:8:10;;;;2296:236;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;2296:236:10;;;2286:247;;49:4:-1;2286:247:10;;;;2256:27;:277;-1:-1:-1;838:227:0;;146:263:-1;;261:2;249:9;240:7;236:23;232:32;229:2;;;-1:-1;;267:12;229:2;89:6;83:13;-1:-1;;;;;5679:5;5285:54;5654:5;5651:35;5641:2;;-1:-1;;5690:12;5641:2;319:74;223:186;-1:-1;;;223:186;2777:661;505:58;;;3077:2;3068:12;;505:58;;;;3179:12;;;505:58;3290:12;;;505:58;3401:12;;;2968:470;3445:1440;2506:66;2486:87;;872:66;2470:2;2592:12;;852:87;2097:66;958:12;;;2077:87;1281:66;2183:12;;;1261:87;1689:66;1367:12;;;1669:87;1775:11;;;4029:856;;838:227:0;;;;;;" + "object": "0x60806040523480156200001157600080fd5b506040516020806200235b833981018060405262000033919081019062000252565b600080546001600160a01b0319166001600160a01b0383161790556040516200005f906020016200029f565b60408051601f1981840301815282825280516020918201208383018352601784527f30782050726f746f636f6c20436f6f7264696e61746f720000000000000000009382019390935281518083018352600581527f312e302e300000000000000000000000000000000000000000000000000000009082015290516200012d92917f626d101e477fd17dd52afb3f9ad9eb016bf60f6e377877f34e8f3ea84c930236917f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c9130910162000284565b60408051601f198184030181529082905280516020918201206001556200015591016200029f565b60408051601f1981840301815282825280516020918201208383018352600b84527f30782050726f746f636f6c0000000000000000000000000000000000000000009382019390935281518083018352600181527f32000000000000000000000000000000000000000000000000000000000000009082015260005491516200023093927ff0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61e927fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5926001600160a01b03909216910162000284565b60408051601f1981840301815291905280516020909101206002555062000360565b6000602082840312156200026557600080fd5b81516001600160a01b03811681146200027d57600080fd5b9392505050565b93845260208401929092526040830152606082015260800190565b7f454950373132446f6d61696e280000000000000000000000000000000000000081527f737472696e67206e616d652c0000000000000000000000000000000000000000600d8201527f737472696e672076657273696f6e2c000000000000000000000000000000000060198201527f6164647265737320766572696679696e67436f6e74726163740000000000000060288201527f2900000000000000000000000000000000000000000000000000000000000000604182015260420190565b611feb80620003706000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c26cfecd1161005b578063c26cfecd146100fe578063d2df073314610106578063ee55b96814610119578063fb6961cc1461013957610088565b80630f7d8e391461008d57806323872f55146100b657806348a321d6146100d657806390c3bc3f146100e9575b600080fd5b6100a061009b3660046115d7565b610141565b6040516100ad9190611958565b60405180910390f35b6100c96100c436600461177c565b6104d4565b6040516100ad9190611aad565b6100c96100e436600461165b565b6104e7565b6100fc6100f73660046117b1565b6104fa565b005b6100c96105a6565b6100fc6101143660046117b1565b6105ac565b61012c61012736600461161e565b6105db565b6040516100ad9190611979565b6100c9610a8f565b600080825111610186576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d7d565b60405180910390fd5b600061019183610a95565b60f81c9050600481106101d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b60008160ff1660048111156101e157fe5b905060008160048111156101f157fe5b1415610229576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611d46565b600181600481111561023757fe5b14156102a857835115610276576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611e48565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611db4565b60028160048111156102b657fe5b14156103bb5783516041146102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061030657fe5b016020015160f890811c811b901c9050600061032986600163ffffffff610b1816565b9050600061033e87602163ffffffff610b1816565b9050600188848484604051600081526020016040526040516103639493929190611ab6565b6020604051602081039080840390855afa158015610385573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015196506104ce95505050505050565b60038160048111156103c957fe5b141561049c57835160411461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ad4565b60008460008151811061041957fe5b016020015160f890811c811b901c9050600061043c86600163ffffffff610b1816565b9050600061045187602163ffffffff610b1816565b90506001886040516020016104669190611927565b60405160208183030381529060405280519060200120848484604051600081526020016040526040516103639493929190611ab6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c7b565b92915050565b60006104ce6104e283610b61565b610bcf565b60006104ce6104f583610bdd565b610c3c565b61050785858585856105ac565b6000548551602087015160408089015190517fbfc8bfce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9094169363bfc8bfce9361056d93909290918990600401611e7f565b600060405180830381600087803b15801561058757600080fd5b505af115801561059b573d6000803e3d6000fd5b505050505050505050565b60025481565b60606105bb86604001516105db565b8051909150156105d3576105d3868287878787610c4a565b505050505050565b606060006105ef838263ffffffff610e9816565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000148061068257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b806106ce57507fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc1500000000000000000000000000000000000000000000000000000000145b15610757576106db6111db565b83516106f190859060049063ffffffff610f0316565b80602001905161070491908101906116ed565b604080516001808252818301909252919250816020015b6107236111db565b81526020019060019003908161071b579050509250808360008151811061074657fe5b602002602001018190525050610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b0000000000000000000000000000000000000000000000000000000014806107e857507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b8061083457507fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae54600000000000000000000000000000000000000000000000000000000145b8061088057507fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000145b806108cc57507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b8061091857507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061096457507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b1561099957825161097f90849060049063ffffffff610f0316565b806020019051610992919081019061154b565b9150610a89565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610a89576109eb6111db565b6109f36111db565b8451610a0990869060049063ffffffff610f0316565b806020019051610a1c9190810190611722565b60408051600280825260608201909252929450909250816020015b610a3f6111db565b815260200190600190039081610a375790505093508184600081518110610a6257fe5b60200260200101819052508084600181518110610a7b57fe5b602002602001018190525050505b50919050565b60015481565b600080825111610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611ce9565b81600183510381518110610ae157fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019092525060f890811c901b90565b60008160200183511015610b58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611c1e565b50016020015190565b604081810151825160209384015182519285019290922083517f213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c81529485019190915273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260608201526080902090565b60006104ce60025483610fcf565b604080820151825160208085015160608681015185519584019590952086517f2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e058152938401949094529482015292830152608082015260a09020919050565b60006104ce60015483610fcf565b3273ffffffffffffffffffffffffffffffffffffffff851614610c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611cb2565b6000610ca4876104d4565b60408051600080825260208201909252845192935091905b818114610da5576000868281518110610cd157fe5b60200260200101519050610ce3611294565b60405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018a8152602001838152509050428211610d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611be7565b6000610d60826104e7565b90506000610d81828a8781518110610d7457fe5b6020026020010151610141565b9050610d93878263ffffffff61100916565b96505060019093019250610cbc915050565b50610db6823263ffffffff61100916565b885190925060005b818114610e8b57600073ffffffffffffffffffffffffffffffffffffffff168a8281518110610de957fe5b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff161415610e1657610e83565b60008a8281518110610e2457fe5b60200260200101516040015190506000610e4782876110d090919063ffffffff16565b905080610e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b0b565b50505b600101610dbe565b5050505050505050505050565b60008160040183511015610ed8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611deb565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b606081831115610f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b42565b8351821115610f7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611b79565b8282036040519080825280601f01601f191660200182016040528015610fa7576020820181803883390190505b509050610fc8610fb682611111565b84610fc087611111565b018351611117565b9392505050565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b81516040516060918490602080820280840182019291018285101561105a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017d90611bb0565b828511156110745761106d858583611117565b8497508793505b6001820191506020810190508084019250829450818852846040528688600184038151811061109f57fe5b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250959695505050505050565b60006020835102602084018181018192505b80831015611108578251808614156110fc57600194508193505b506020830192506110e2565b50505092915050565b60200190565b6020811015611141576001816020036101000a0380198351168185511680821786525050506111d6565b8282141561114e576111d6565b828211156111885760208103905080820181840181515b82851015611180578451865260209586019590940193611165565b9052506111d6565b60208103905080820181840183515b818612156111d157825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09283019290910190611197565b855250505b505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000801916815260200160608152602001600081525090565b80516104ce81611f8c565b600082601f8301126112f0578081fd5b81356113036112fe82611ef8565b611ed1565b8181529150602080830190840160005b838110156113405761132b876020843589010161134a565b83526020928301929190910190600101611313565b5050505092915050565b600082601f83011261135a578081fd5b81356113686112fe82611f19565b915080825283602082850101111561137f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f8301126113a957600080fd5b81516113b76112fe82611f19565b91508082528360208285010111156113ce57600080fd5b6113df816020840160208601611f5c565b5092915050565b60006101808083850312156113f9578182fd5b61140281611ed1565b91505061140f83836112d5565b815261141e83602084016112d5565b602082015261143083604084016112d5565b604082015261144283606084016112d5565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff808211156114a457600080fd5b6114b086838701611398565b838501526101609250828501519150808211156114cc57600080fd5b506114d985828601611398565b82840152505092915050565b6000606082840312156114f6578081fd5b6115006060611ed1565b905081358152602082013561151481611f8c565b6020820152604082013567ffffffffffffffff81111561153357600080fd5b61153f8482850161134a565b60408301525092915050565b6000602080838503121561155d578182fd5b825167ffffffffffffffff811115611573578283fd5b80840185601f820112611584578384fd5b805191506115946112fe83611ef8565b82815283810190828501865b858110156115c9576115b78a8884518801016113e6565b845292860192908601906001016115a0565b509098975050505050505050565b600080604083850312156115ea57600080fd5b82359150602083013567ffffffffffffffff81111561160857600080fd5b6116148582860161134a565b9150509250929050565b60006020828403121561163057600080fd5b813567ffffffffffffffff81111561164757600080fd5b6116538482850161134a565b949350505050565b60006020828403121561166c578081fd5b813567ffffffffffffffff80821115611683578283fd5b81840160808187031215611695578384fd5b61169f6080611ed1565b925080356116ac81611f8c565b8352602081810135908401526040810135828111156116c9578485fd5b6116d58782840161134a565b60408501525060609081013590830152509392505050565b6000602082840312156116ff57600080fd5b815167ffffffffffffffff81111561171657600080fd5b611653848285016113e6565b6000806040838503121561173557600080fd5b825167ffffffffffffffff8082111561174d57600080fd5b611759868387016113e6565b9350602085015191508082111561176f57600080fd5b50611614858286016113e6565b60006020828403121561178e57600080fd5b813567ffffffffffffffff8111156117a557600080fd5b611653848285016114e5565b600080600080600060a086880312156117c8578081fd5b853567ffffffffffffffff808211156117df578283fd5b6117eb89838a016114e5565b965060209150818801356117fe81611f8c565b9550604088013581811115611811578384fd5b61181d8a828b0161134a565b955050606088013581811115611831578384fd5b8089018a601f820112611842578485fd5b803591506118526112fe83611ef8565b82815284810190828601868502840187018e101561186e578788fd5b8793505b84841015611890578035835260019390930192918601918601611872565b50965050505060808801359150808211156118a9578283fd5b506118b6888289016112e0565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff169052565b600081518084526118f5816020860160208601611f5c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b82811015611aa0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845281516101806119de8783516118c3565b878201516119ee898901826118c3565b506040820151611a0160408901826118c3565b506060820151611a1460608901826118c3565b506080820151608088015260a082015160a088015260c082015160c088015260e082015160e08801526101008083015181890152506101208083015181890152506101408083015182828a0152611a6d838a01826118dd565b915050610160915081830151888203838a0152611a8a82826118dd565b985050509487019450509085019060010161199f565b5092979650505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526012908201527f4c454e4754485f36355f52455155495245440000000000000000000000000000604082015260600190565b6020808252601a908201527f494e56414c49445f415050524f56414c5f5349474e4154555245000000000000604082015260600190565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526017908201527f494e56414c49445f465245455f4d454d4f52595f505452000000000000000000604082015260600190565b60208082526010908201527f415050524f56414c5f4558504952454400000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526015908201527f5349474e41545552455f554e535550504f525445440000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f4f524947494e000000000000000000000000000000000000604082015260600190565b60208082526021908201527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560408201527f4400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f5349474e41545552455f494c4c4547414c000000000000000000000000000000604082015260600190565b6020808252601e908201527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000604082015260600190565b60208082526011908201527f5349474e41545552455f494e56414c4944000000000000000000000000000000604082015260600190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f4c454e4754485f305f5245515549524544000000000000000000000000000000604082015260600190565b600085825273ffffffffffffffffffffffffffffffffffffffff8516602083015260806040830152611eb460808301856118dd565b8281036060840152611ec681856118dd565b979650505050505050565b60405181810167ffffffffffffffff81118282101715611ef057600080fd5b604052919050565b600067ffffffffffffffff821115611f0f57600080fd5b5060209081020190565b600067ffffffffffffffff821115611f3057600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015611f77578181015183820152602001611f5f565b83811115611f86576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611fae57600080fd5b5056fea265627a7a72305820bcdb4aab3e1a04ea5cd6c138911116ceac3fac88de1995c4d3f24fdd3f420fb66c6578706572696d656e74616cf50037" }, "deployedBytecode": { "linkReferences": {}, @@ -308,118 +306,6 @@ } } }, - "sources": { - "src/Coordinator.sol": { - "id": 0 - }, - "src/libs/LibConstants.sol": { - "id": 8 - }, - "src/interfaces/ITransactions.sol": { - "id": 7 - }, - "src/MixinSignatureValidator.sol": { - "id": 3 - }, - "@0x/contracts-utils/contracts/src/LibBytes.sol": { - "id": 21 - }, - "src/mixins/MSignatureValidator.sol": { - "id": 13 - }, - "src/interfaces/ISignatureValidator.sol": { - "id": 6 - }, - "src/MixinCoordinatorApprovalVerifier.sol": { - "id": 1 - }, - "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": { - "id": 18 - }, - "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": { - "id": 19 - }, - "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": { - "id": 17 - }, - "@0x/contracts-utils/contracts/src/LibAddressArray.sol": { - "id": 20 - }, - "src/libs/LibCoordinatorApproval.sol": { - "id": 9 - }, - "src/libs/LibEIP712Domain.sol": { - "id": 10 - }, - "src/libs/LibZeroExTransaction.sol": { - "id": 11 - }, - "src/mixins/MCoordinatorApprovalVerifier.sol": { - "id": 12 - }, - "src/interfaces/ICoordinatorApprovalVerifier.sol": { - "id": 4 - }, - "src/MixinCoordinatorCore.sol": { - "id": 2 - }, - "src/interfaces/ICoordinatorCore.sol": { - "id": 5 - } - }, - "sourceCodes": { - "src/Coordinator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibConstants.sol\";\nimport \"./MixinSignatureValidator.sol\";\nimport \"./MixinCoordinatorApprovalVerifier.sol\";\nimport \"./MixinCoordinatorCore.sol\";\n\n\n// solhint-disable no-empty-blocks\ncontract Coordinator is\n LibConstants,\n MixinSignatureValidator,\n MixinCoordinatorApprovalVerifier,\n MixinCoordinatorCore\n{\n constructor (address _exchange)\n public\n LibConstants(_exchange)\n {}\n}\n", - "src/libs/LibConstants.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ITransactions.sol\";\n\n\ncontract LibConstants {\n\n // solhint-disable-next-line var-name-mixedcase\n ITransactions internal EXCHANGE;\n\n constructor (address _exchange)\n public\n {\n EXCHANGE = ITransactions(_exchange);\n }\n}\n", - "src/interfaces/ITransactions.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\npragma solidity ^0.5.5;\n\n\ncontract ITransactions {\n\n /// @dev Executes an exchange method call in the context of signer.\n /// @param salt Arbitrary number to ensure uniqueness of transaction hash.\n /// @param signerAddress Address of transaction signer.\n /// @param data AbiV2 encoded calldata.\n /// @param signature Proof of signer transaction by signer.\n function executeTransaction(\n uint256 salt,\n address signerAddress,\n bytes calldata data,\n bytes calldata signature\n )\n external;\n}\n", - "src/MixinSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\n\n\ncontract MixinSignatureValidator is\n MSignatureValidator\n{\n using LibBytes for bytes;\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress)\n {\n require(\n signature.length > 0,\n \"LENGTH_GREATER_THAN_0_REQUIRED\"\n );\n\n // Pop last byte off of signature byte array.\n uint8 signatureTypeRaw = uint8(signature.popLastByte());\n\n // Ensure signature is supported\n require(\n signatureTypeRaw < uint8(SignatureType.NSignatureTypes),\n \"SIGNATURE_UNSUPPORTED\"\n );\n\n SignatureType signatureType = SignatureType(signatureTypeRaw);\n\n // Always illegal signature.\n // This is always an implicit option since a signer can create a\n // signature array with invalid type or length. We may as well make\n // it an explicit option. This aids testing and analysis. It is\n // also the initialization value for the enum type.\n if (signatureType == SignatureType.Illegal) {\n revert(\"SIGNATURE_ILLEGAL\");\n\n // Always invalid signature.\n // Like Illegal, this is always implicitly available and therefore\n // offered explicitly. It can be implicitly created by providing\n // a correctly formatted but incorrect signature.\n } else if (signatureType == SignatureType.Invalid) {\n require(\n signature.length == 0,\n \"LENGTH_0_REQUIRED\"\n );\n revert(\"SIGNATURE_INVALID\");\n\n // Signature using EIP712\n } else if (signatureType == SignatureType.EIP712) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n hash,\n v,\n r,\n s\n );\n return signerAddress;\n\n // Signed using web3.eth_sign\n } else if (signatureType == SignatureType.EthSign) {\n require(\n signature.length == 65,\n \"LENGTH_65_REQUIRED\"\n );\n uint8 v = uint8(signature[0]);\n bytes32 r = signature.readBytes32(1);\n bytes32 s = signature.readBytes32(33);\n signerAddress = ecrecover(\n keccak256(abi.encodePacked(\n \"\\x19Ethereum Signed Message:\\n32\",\n hash\n )),\n v,\n r,\n s\n );\n return signerAddress;\n }\n\n // Anything else is illegal (We do not return false because\n // the signature may actually be valid, just not in a format\n // that we currently support. In this case returning false\n // may lead the caller to incorrectly believe that the\n // signature was invalid.)\n revert(\"SIGNATURE_UNSUPPORTED\");\n }\n}\n", - "@0x/contracts-utils/contracts/src/LibBytes.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\nlibrary LibBytes {\n\n using LibBytes for bytes;\n\n /// @dev Gets the memory address for a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of byte array. This\n /// points to the header of the byte array which contains\n /// the length.\n function rawAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := input\n }\n return memoryAddress;\n }\n \n /// @dev Gets the memory address for the contents of a byte array.\n /// @param input Byte array to lookup.\n /// @return memoryAddress Memory address of the contents of the byte array.\n function contentAddress(bytes memory input)\n internal\n pure\n returns (uint256 memoryAddress)\n {\n assembly {\n memoryAddress := add(input, 32)\n }\n return memoryAddress;\n }\n\n /// @dev Copies `length` bytes from memory location `source` to `dest`.\n /// @param dest memory address to copy bytes to.\n /// @param source memory address to copy bytes from.\n /// @param length number of bytes to copy.\n function memCopy(\n uint256 dest,\n uint256 source,\n uint256 length\n )\n internal\n pure\n {\n if (length < 32) {\n // Handle a partial word by reading destination and masking\n // off the bits we are interested in.\n // This correctly handles overlap, zero lengths and source == dest\n assembly {\n let mask := sub(exp(256, sub(32, length)), 1)\n let s := and(mload(source), not(mask))\n let d := and(mload(dest), mask)\n mstore(dest, or(s, d))\n }\n } else {\n // Skip the O(length) loop when source == dest.\n if (source == dest) {\n return;\n }\n\n // For large copies we copy whole words at a time. The final\n // word is aligned to the end of the range (instead of after the\n // previous) to handle partial words. So a copy will look like this:\n //\n // ####\n // ####\n // ####\n // ####\n //\n // We handle overlap in the source and destination range by\n // changing the copying direction. This prevents us from\n // overwriting parts of source that we still need to copy.\n //\n // This correctly handles source == dest\n //\n if (source > dest) {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because it\n // is easier to compare with in the loop, and these\n // are also the addresses we need for copying the\n // last bytes.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the last 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the last bytes in\n // source already due to overlap.\n let last := mload(sEnd)\n\n // Copy whole words front to back\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} lt(source, sEnd) {} {\n mstore(dest, mload(source))\n source := add(source, 32)\n dest := add(dest, 32)\n }\n \n // Write the last 32 bytes\n mstore(dEnd, last)\n }\n } else {\n assembly {\n // We subtract 32 from `sEnd` and `dEnd` because those\n // are the starting points when copying a word at the end.\n length := sub(length, 32)\n let sEnd := add(source, length)\n let dEnd := add(dest, length)\n\n // Remember the first 32 bytes of source\n // This needs to be done here and not after the loop\n // because we may have overwritten the first bytes in\n // source already due to overlap.\n let first := mload(source)\n\n // Copy whole words back to front\n // We use a signed comparisson here to allow dEnd to become\n // negative (happens when source and dest < 32). Valid\n // addresses in local memory will never be larger than\n // 2**255, so they can be safely re-interpreted as signed.\n // Note: the first check is always true,\n // this could have been a do-while loop.\n // solhint-disable-next-line no-empty-blocks\n for {} slt(dest, dEnd) {} {\n mstore(dEnd, mload(sEnd))\n sEnd := sub(sEnd, 32)\n dEnd := sub(dEnd, 32)\n }\n \n // Write the first 32 bytes\n mstore(dest, first)\n }\n }\n }\n }\n\n /// @dev Returns a slices from a byte array.\n /// @param b The byte array to take a slice from.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n function slice(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure and copy contents\n result = new bytes(to - from);\n memCopy(\n result.contentAddress(),\n b.contentAddress() + from,\n result.length\n );\n return result;\n }\n \n /// @dev Returns a slice from a byte array without preserving the input.\n /// @param b The byte array to take a slice from. Will be destroyed in the process.\n /// @param from The starting index for the slice (inclusive).\n /// @param to The final index for the slice (exclusive).\n /// @return result The slice containing bytes at indices [from, to)\n /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted.\n function sliceDestructive(\n bytes memory b,\n uint256 from,\n uint256 to\n )\n internal\n pure\n returns (bytes memory result)\n {\n require(\n from <= to,\n \"FROM_LESS_THAN_TO_REQUIRED\"\n );\n require(\n to <= b.length,\n \"TO_LESS_THAN_LENGTH_REQUIRED\"\n );\n \n // Create a new bytes structure around [from, to) in-place.\n assembly {\n result := add(b, from)\n mstore(result, sub(to, from))\n }\n return result;\n }\n\n /// @dev Pops the last byte off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The byte that was popped off.\n function popLastByte(bytes memory b)\n internal\n pure\n returns (bytes1 result)\n {\n require(\n b.length > 0,\n \"GREATER_THAN_ZERO_LENGTH_REQUIRED\"\n );\n\n // Store last byte.\n result = b[b.length - 1];\n\n assembly {\n // Decrement length of byte array.\n let newLen := sub(mload(b), 1)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Pops the last 20 bytes off of a byte array by modifying its length.\n /// @param b Byte array that will be modified.\n /// @return The 20 byte address that was popped off.\n function popLast20Bytes(bytes memory b)\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= 20,\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Store last 20 bytes.\n result = readAddress(b, b.length - 20);\n\n assembly {\n // Subtract 20 from byte array length.\n let newLen := sub(mload(b), 20)\n mstore(b, newLen)\n }\n return result;\n }\n\n /// @dev Tests equality of two byte arrays.\n /// @param lhs First byte array to compare.\n /// @param rhs Second byte array to compare.\n /// @return True if arrays are the same. False otherwise.\n function equals(\n bytes memory lhs,\n bytes memory rhs\n )\n internal\n pure\n returns (bool equal)\n {\n // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare.\n // We early exit on unequal lengths, but keccak would also correctly\n // handle this.\n return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs);\n }\n\n /// @dev Reads an address from a position in a byte array.\n /// @param b Byte array containing an address.\n /// @param index Index in byte array of address.\n /// @return address from byte array.\n function readAddress(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (address result)\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Read address from array memory\n assembly {\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 20-byte mask to obtain address\n result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n return result;\n }\n\n /// @dev Writes an address into a specific position in a byte array.\n /// @param b Byte array to insert address into.\n /// @param index Index in byte array of address.\n /// @param input Address to put into byte array.\n function writeAddress(\n bytes memory b,\n uint256 index,\n address input\n )\n internal\n pure\n {\n require(\n b.length >= index + 20, // 20 is length of address\n \"GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED\"\n );\n\n // Add offset to index:\n // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)\n // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)\n index += 20;\n\n // Store address into array memory\n assembly {\n // The address occupies 20 bytes and mstore stores 32 bytes.\n // First fetch the 32-byte word where we'll be storing the address, then\n // apply a mask so we have only the bytes in the word that the address will not occupy.\n // Then combine these bytes with the address and store the 32 bytes back to memory with mstore.\n\n // 1. Add index to address of bytes array\n // 2. Load 32-byte word from memory\n // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address\n let neighbors := and(\n mload(add(b, index)),\n 0xffffffffffffffffffffffff0000000000000000000000000000000000000000\n )\n \n // Make sure input address is clean.\n // (Solidity does not guarantee this)\n input := and(input, 0xffffffffffffffffffffffffffffffffffffffff)\n\n // Store the neighbors and address into memory\n mstore(add(b, index), xor(input, neighbors))\n }\n }\n\n /// @dev Reads a bytes32 value from a position in a byte array.\n /// @param b Byte array containing a bytes32 value.\n /// @param index Index in byte array of bytes32 value.\n /// @return bytes32 value from byte array.\n function readBytes32(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes32 result)\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n result := mload(add(b, index))\n }\n return result;\n }\n\n /// @dev Writes a bytes32 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes32 to put into byte array.\n function writeBytes32(\n bytes memory b,\n uint256 index,\n bytes32 input\n )\n internal\n pure\n {\n require(\n b.length >= index + 32,\n \"GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 256 bit length parameter\n index += 32;\n\n // Read the bytes32 from array memory\n assembly {\n mstore(add(b, index), input)\n }\n }\n\n /// @dev Reads a uint256 value from a position in a byte array.\n /// @param b Byte array containing a uint256 value.\n /// @param index Index in byte array of uint256 value.\n /// @return uint256 value from byte array.\n function readUint256(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (uint256 result)\n {\n result = uint256(readBytes32(b, index));\n return result;\n }\n\n /// @dev Writes a uint256 into a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input uint256 to put into byte array.\n function writeUint256(\n bytes memory b,\n uint256 index,\n uint256 input\n )\n internal\n pure\n {\n writeBytes32(b, index, bytes32(input));\n }\n\n /// @dev Reads an unpadded bytes4 value from a position in a byte array.\n /// @param b Byte array containing a bytes4 value.\n /// @param index Index in byte array of bytes4 value.\n /// @return bytes4 value from byte array.\n function readBytes4(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes4 result)\n {\n require(\n b.length >= index + 4,\n \"GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED\"\n );\n\n // Arrays are prefixed by a 32 byte length field\n index += 32;\n\n // Read the bytes4 from array memory\n assembly {\n result := mload(add(b, index))\n // Solidity does not require us to clean the trailing bytes.\n // We do it anyway\n result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)\n }\n return result;\n }\n\n /// @dev Reads nested bytes from a specific position.\n /// @dev NOTE: the returned value overlaps with the input value.\n /// Both should be treated as immutable.\n /// @param b Byte array containing nested bytes.\n /// @param index Index of nested bytes.\n /// @return result Nested bytes.\n function readBytesWithLength(\n bytes memory b,\n uint256 index\n )\n internal\n pure\n returns (bytes memory result)\n {\n // Read length of nested bytes\n uint256 nestedBytesLength = readUint256(b, index);\n index += 32;\n\n // Assert length of is valid, given\n // length of nested bytes\n require(\n b.length >= index + nestedBytesLength,\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n \n // Return a pointer to the byte array as it exists inside `b`\n assembly {\n result := add(b, index)\n }\n return result;\n }\n\n /// @dev Inserts bytes at a specific position in a byte array.\n /// @param b Byte array to insert into.\n /// @param index Index in byte array of .\n /// @param input bytes to insert.\n function writeBytesWithLength(\n bytes memory b,\n uint256 index,\n bytes memory input\n )\n internal\n pure\n {\n // Assert length of is valid, given\n // length of input\n require(\n b.length >= index + 32 + input.length, // 32 bytes to store length\n \"GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED\"\n );\n\n // Copy into \n memCopy(\n b.contentAddress() + index,\n input.rawAddress(), // includes length of \n input.length + 32 // +32 bytes to store length\n );\n }\n\n /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.\n /// @param dest Byte array that will be overwritten with source bytes.\n /// @param source Byte array to copy onto dest bytes.\n function deepCopyBytes(\n bytes memory dest,\n bytes memory source\n )\n internal\n pure\n {\n uint256 sourceLen = source.length;\n // Dest length must be >= source length, or some bytes would not be copied.\n require(\n dest.length >= sourceLen,\n \"GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED\"\n );\n memCopy(\n dest.contentAddress(),\n source.contentAddress(),\n sourceLen\n );\n }\n}\n", - "src/mixins/MSignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"../interfaces/ISignatureValidator.sol\";\n\n\ncontract MSignatureValidator is\n ISignatureValidator\n{\n // Allowed signature types.\n enum SignatureType {\n Illegal, // 0x00, default value\n Invalid, // 0x01\n EIP712, // 0x02\n EthSign, // 0x03\n NSignatureTypes // 0x04, number of signature types. Always leave at end.\n }\n}\n", - "src/interfaces/ISignatureValidator.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract ISignatureValidator {\n\n /// @dev Recovers the address of a signer given a hash and signature.\n /// @param hash Any 32 byte hash.\n /// @param signature Proof that the hash has been signed by signer.\n function getSignerAddress(bytes32 hash, bytes memory signature)\n public\n pure\n returns (address signerAddress);\n}\n", - "src/MixinCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol\";\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibBytes.sol\";\nimport \"@0x/contracts-utils/contracts/src/LibAddressArray.sol\";\nimport \"./libs/LibCoordinatorApproval.sol\";\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./mixins/MSignatureValidator.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\n\n\n// solhint-disable avoid-tx-origin\ncontract MixinCoordinatorApprovalVerifier is\n LibExchangeSelectors,\n LibCoordinatorApproval,\n LibZeroExTransaction,\n MSignatureValidator,\n MCoordinatorApprovalVerifier\n{\n using LibBytes for bytes;\n using LibAddressArray for address[];\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view\n {\n // Get the orders from the the Exchange calldata in the 0x transaction\n LibOrder.Order[] memory orders = decodeOrdersFromFillData(transaction.data);\n\n // No approval is required for non-fill methods\n if (orders.length > 0) {\n // Revert if approval is invalid for transaction orders\n assertValidTransactionOrdersApproval(\n transaction,\n orders,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n }\n }\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders)\n {\n bytes4 selector = data.readBytes4(0);\n if (\n selector == FILL_ORDER_SELECTOR ||\n selector == FILL_ORDER_NO_THROW_SELECTOR ||\n selector == FILL_OR_KILL_ORDER_SELECTOR\n ) {\n // Decode single order\n (LibOrder.Order memory order) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order)\n );\n orders = new LibOrder.Order[](1);\n orders[0] = order;\n } else if (\n selector == BATCH_FILL_ORDERS_SELECTOR ||\n selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||\n selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_SELECTOR ||\n selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||\n selector == MARKET_SELL_ORDERS_SELECTOR ||\n selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR\n ) {\n // Decode all orders\n // solhint-disable indent\n (orders) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order[])\n );\n } else if (selector == MATCH_ORDERS_SELECTOR) {\n // Decode left and right orders\n (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(\n data.slice(4, data.length),\n (LibOrder.Order, LibOrder.Order)\n );\n\n // Create array of orders\n orders = new LibOrder.Order[](2);\n orders[0] = leftOrder;\n orders[1] = rightOrder;\n }\n return orders;\n }\n\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view\n {\n // Verify that Ethereum tx signer is the same as the approved txOrigin\n require(\n tx.origin == txOrigin,\n \"INVALID_ORIGIN\"\n );\n\n // Hash 0x transaction\n bytes32 transactionHash = getTransactionHash(transaction);\n\n // Create empty list of approval signers\n address[] memory approvalSignerAddresses = new address[](0);\n\n uint256 signaturesLength = approvalSignatures.length;\n for (uint256 i = 0; i != signaturesLength; i++) {\n // Create approval message\n uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i];\n CoordinatorApproval memory approval = CoordinatorApproval({\n txOrigin: txOrigin,\n transactionHash: transactionHash,\n transactionSignature: transactionSignature,\n approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds\n });\n\n // Ensure approval has not expired\n require(\n // solhint-disable-next-line not-rely-on-time\n currentApprovalExpirationTimeSeconds > block.timestamp,\n \"APPROVAL_EXPIRED\"\n );\n\n // Hash approval message and recover signer address\n bytes32 approvalHash = getCoordinatorApprovalHash(approval);\n address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]);\n\n // Add approval signer to list of signers\n approvalSignerAddresses = approvalSignerAddresses.append(approvalSignerAddress);\n }\n\n // Ethereum transaction signer gives implicit signature of approval\n approvalSignerAddresses = approvalSignerAddresses.append(tx.origin);\n\n uint256 ordersLength = orders.length;\n for (uint256 i = 0; i != ordersLength; i++) {\n // Do not check approval if the order's senderAddress is null\n if (orders[i].senderAddress == address(0)) {\n continue;\n }\n\n // Ensure feeRecipient of order has approved this 0x transaction\n address approverAddress = orders[i].feeRecipientAddress;\n bool isOrderApproved = approvalSignerAddresses.contains(approverAddress);\n require(\n isOrderApproved,\n \"INVALID_APPROVAL_SIGNATURE\"\n );\n }\n }\n}\n", - "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibExchangeSelectors {\n\n // solhint-disable max-line-length\n // allowedValidators\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514;\n bytes4 constant internal ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256(\"allowedValidators(address,address)\"));\n\n // assetProxies\n bytes4 constant internal ASSET_PROXIES_SELECTOR = 0x3fd3c997;\n bytes4 constant internal ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256(\"assetProxies(bytes4)\"));\n\n // batchCancelOrders\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782;\n bytes4 constant internal BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // batchFillOrKillOrders\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546;\n bytes4 constant internal BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrders\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b;\n bytes4 constant internal BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // batchFillOrdersNoThrow\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190;\n bytes4 constant internal BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])\"));\n\n // cancelOrder\n bytes4 constant internal CANCEL_ORDER_SELECTOR = 0xd46b02c3;\n bytes4 constant internal CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // cancelOrdersUpTo\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1;\n bytes4 constant internal CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelOrdersUpTo(uint256)\"));\n\n // cancelled\n bytes4 constant internal CANCELLED_SELECTOR = 0x2ac12622;\n bytes4 constant internal CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256(\"cancelled(bytes32)\"));\n\n // currentContextAddress\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba;\n bytes4 constant internal CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256(\"currentContextAddress()\"));\n\n // executeTransaction\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce;\n bytes4 constant internal EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256(\"executeTransaction(uint256,address,bytes,bytes)\"));\n\n // fillOrKillOrder\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15;\n bytes4 constant internal FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrder\n bytes4 constant internal FILL_ORDER_SELECTOR = 0xb4be83d5;\n bytes4 constant internal FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // fillOrderNoThrow\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae;\n bytes4 constant internal FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)\"));\n\n // filled\n bytes4 constant internal FILLED_SELECTOR = 0x288cdc91;\n bytes4 constant internal FILLED_SELECTOR_GENERATOR = bytes4(keccak256(\"filled(bytes32)\"));\n\n // getAssetProxy\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR = 0x60704108;\n bytes4 constant internal GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"getAssetProxy(bytes4)\"));\n\n // getOrderInfo\n bytes4 constant internal GET_ORDER_INFO_SELECTOR = 0xc75e0a81;\n bytes4 constant internal GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))\"));\n\n // getOrdersInfo\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc;\n bytes4 constant internal GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256(\"getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])\"));\n\n // isValidSignature\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR = 0x93634702;\n bytes4 constant internal IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256(\"isValidSignature(bytes32,address,bytes)\"));\n\n // marketBuyOrders\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b;\n bytes4 constant internal MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketBuyOrdersNoThrow\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380;\n bytes4 constant internal MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrders\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808;\n bytes4 constant internal MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // marketSellOrdersNoThrow\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18;\n bytes4 constant internal MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256(\"marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])\"));\n\n // matchOrders\n bytes4 constant internal MATCH_ORDERS_SELECTOR = 0x3c28d861;\n bytes4 constant internal MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256(\"matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)\"));\n\n // orderEpoch\n bytes4 constant internal ORDER_EPOCH_SELECTOR = 0xd9bfa73e;\n bytes4 constant internal ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256(\"orderEpoch(address,address)\"));\n\n // owner\n bytes4 constant internal OWNER_SELECTOR = 0x8da5cb5b;\n bytes4 constant internal OWNER_SELECTOR_GENERATOR = bytes4(keccak256(\"owner()\"));\n\n // preSign\n bytes4 constant internal PRE_SIGN_SELECTOR = 0x3683ef8e;\n bytes4 constant internal PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256(\"preSign(bytes32,address,bytes)\"));\n\n // preSigned\n bytes4 constant internal PRE_SIGNED_SELECTOR = 0x82c174d0;\n bytes4 constant internal PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256(\"preSigned(bytes32,address)\"));\n\n // registerAssetProxy\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93;\n bytes4 constant internal REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256(\"registerAssetProxy(address)\"));\n\n // setSignatureValidatorApproval\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68;\n bytes4 constant internal SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256(\"setSignatureValidatorApproval(address,bool)\"));\n\n // transactions\n bytes4 constant internal TRANSACTIONS_SELECTOR = 0x642f2eaf;\n bytes4 constant internal TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256(\"transactions(bytes32)\"));\n\n // transferOwnership\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;\n bytes4 constant internal TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256(\"transferOwnership(address)\"));\n}", - "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibEIP712.sol\";\n\n\ncontract LibOrder is\n LibEIP712\n{\n // Hash for the EIP712 Order Schema\n bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"Order(\",\n \"address makerAddress,\",\n \"address takerAddress,\",\n \"address feeRecipientAddress,\",\n \"address senderAddress,\",\n \"uint256 makerAssetAmount,\",\n \"uint256 takerAssetAmount,\",\n \"uint256 makerFee,\",\n \"uint256 takerFee,\",\n \"uint256 expirationTimeSeconds,\",\n \"uint256 salt,\",\n \"bytes makerAssetData,\",\n \"bytes takerAssetData\",\n \")\"\n ));\n\n // A valid order remains fillable until it is expired, fully filled, or cancelled.\n // An order's state is unaffected by external factors, like account balances.\n enum OrderStatus {\n INVALID, // Default value\n INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount\n INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount\n FILLABLE, // Order is fillable\n EXPIRED, // Order has already expired\n FULLY_FILLED, // Order is fully filled\n CANCELLED // Order has been cancelled\n }\n\n // solhint-disable max-line-length\n struct Order {\n address makerAddress; // Address that created the order. \n address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order. \n address feeRecipientAddress; // Address that will recieve fees when order is filled. \n address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.\n uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0. \n uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0. \n uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.\n uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.\n uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires. \n uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash. \n bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.\n bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.\n }\n // solhint-enable max-line-length\n\n struct OrderInfo {\n uint8 orderStatus; // Status that describes order's validity and fillability.\n bytes32 orderHash; // EIP712 hash of the order (see LibOrder.getOrderHash).\n uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.\n }\n\n /// @dev Calculates Keccak-256 hash of the order.\n /// @param order The order structure.\n /// @return Keccak-256 EIP712 hash of the order.\n function getOrderHash(Order memory order)\n internal\n view\n returns (bytes32 orderHash)\n {\n orderHash = hashEIP712Message(hashOrder(order));\n return orderHash;\n }\n\n /// @dev Calculates EIP712 hash of the order.\n /// @param order The order structure.\n /// @return EIP712 hash of the order.\n function hashOrder(Order memory order)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;\n bytes32 makerAssetDataHash = keccak256(order.makerAssetData);\n bytes32 takerAssetDataHash = keccak256(order.takerAssetData);\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ORDER_SCHEMA_HASH,\n // bytes32(order.makerAddress),\n // bytes32(order.takerAddress),\n // bytes32(order.feeRecipientAddress),\n // bytes32(order.senderAddress),\n // order.makerAssetAmount,\n // order.takerAssetAmount,\n // order.makerFee,\n // order.takerFee,\n // order.expirationTimeSeconds,\n // order.salt,\n // keccak256(order.makerAssetData),\n // keccak256(order.takerAssetData)\n // ));\n\n assembly {\n // Calculate memory addresses that will be swapped out before hashing\n let pos1 := sub(order, 32)\n let pos2 := add(order, 320)\n let pos3 := add(order, 352)\n\n // Backup\n let temp1 := mload(pos1)\n let temp2 := mload(pos2)\n let temp3 := mload(pos3)\n \n // Hash in place\n mstore(pos1, schemaHash)\n mstore(pos2, makerAssetDataHash)\n mstore(pos3, takerAssetDataHash)\n result := keccak256(pos1, 416)\n \n // Restore\n mstore(pos1, temp1)\n mstore(pos2, temp2)\n mstore(pos3, temp3)\n }\n return result;\n }\n}\n", - "@0x/contracts-exchange-libs/contracts/src/LibEIP712.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\n\ncontract LibEIP712 {\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value\n string constant internal EIP712_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value\n string constant internal EIP712_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_DOMAIN_NAME)),\n keccak256(bytes(EIP712_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712Message(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;\n\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct \n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", - "@0x/contracts-utils/contracts/src/LibAddressArray.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibBytes.sol\";\n\n\nlibrary LibAddressArray {\n\n /// @dev Append a new address to an array of addresses.\n /// The `addressArray` may need to be reallocated to make space\n /// for the new address. Because of this we return the resulting\n /// memory location of `addressArray`.\n /// @param addressArray Array of addresses.\n /// @param addressToAppend Address to append.\n /// @return Array of addresses: [... addressArray, addressToAppend]\n function append(address[] memory addressArray, address addressToAppend)\n internal\n pure\n returns (address[] memory)\n {\n // Get stats on address array and free memory\n uint256 freeMemPtr = 0;\n uint256 addressArrayBeginPtr = 0;\n uint256 addressArrayEndPtr = 0;\n uint256 addressArrayLength = addressArray.length;\n uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);\n assembly {\n freeMemPtr := mload(0x40)\n addressArrayBeginPtr := addressArray\n addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)\n }\n\n // Cases for `freeMemPtr`:\n // `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`\n // `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`\n // `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.\n require(\n freeMemPtr >= addressArrayEndPtr,\n \"INVALID_FREE_MEMORY_PTR\"\n );\n\n // If free memory begins at the end of `addressArray`\n // then we can append `addressToAppend` directly.\n // Otherwise, we must copy the array to free memory\n // before appending new values to it.\n if (freeMemPtr > addressArrayEndPtr) {\n LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);\n assembly {\n addressArray := freeMemPtr\n addressArrayBeginPtr := addressArray\n }\n }\n\n // Append `addressToAppend`\n addressArrayLength += 1;\n addressArrayMemSizeInBytes += 32;\n addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;\n freeMemPtr = addressArrayEndPtr;\n assembly {\n // Store new array length\n mstore(addressArray, addressArrayLength)\n\n // Update `freeMemPtr`\n mstore(0x40, freeMemPtr)\n }\n addressArray[addressArrayLength - 1] = addressToAppend;\n return addressArray;\n }\n\n /// @dev Checks if an address array contains the target address.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return True if the addressArray contains the target.\n function contains(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success to true\n success := 1\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return success;\n }\n\n /// @dev Finds the index of an address within an array.\n /// @param addressArray Array of addresses.\n /// @param target Address to search for in array.\n /// @return Existence and index of the target in the array.\n function indexOf(address[] memory addressArray, address target)\n internal\n pure\n returns (bool success, uint256 index)\n {\n assembly {\n\n // Calculate byte length of array\n let arrayByteLen := mul(mload(addressArray), 32)\n // Calculate beginning of array contents\n let arrayContentsStart := add(addressArray, 32)\n // Calclulate end of array contents\n let arrayContentsEnd := add(arrayContentsStart, arrayByteLen)\n\n // Loop through array\n for {let i:= arrayContentsStart} lt(i, arrayContentsEnd) {i := add(i, 32)} {\n\n // Load array element\n let arrayElement := mload(i)\n\n // Return true if array element equals target\n if eq(target, arrayElement) {\n // Set success and index\n success := 1\n index := div(sub(i, arrayContentsStart), 32)\n // Break loop\n i := arrayContentsEnd\n }\n }\n }\n return (success, index);\n }\n}\n", - "src/libs/LibCoordinatorApproval.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibCoordinatorApproval is\n LibEIP712Domain\n{\n // Hash for the EIP712 Coordinator approval message\n // keccak256(abi.encodePacked(\n // \"CoordinatorApproval(\",\n // \"address txOrigin,\",\n // \"bytes32 transactionHash,\",\n // \"bytes transactionSignature,\",\n // \"uint256 approvalExpirationTimeSeconds\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05;\n\n struct CoordinatorApproval {\n address txOrigin; // Required signer of Ethereum transaction that is submitting approval.\n bytes32 transactionHash; // EIP712 hash of the transaction.\n bytes transactionSignature; // Signature of the 0x transaction.\n uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the approval expires.\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.\n function getCoordinatorApprovalHash(CoordinatorApproval memory approval)\n public\n view\n returns (bytes32 approvalHash)\n {\n approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval));\n return approvalHash;\n }\n\n /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage with no domain separator.\n /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.\n /// @return EIP712 hash of the Coordinator approval message with no domain separator.\n function hashCoordinatorApproval(CoordinatorApproval memory approval)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH;\n bytes memory transactionSignature = approval.transactionSignature;\n address txOrigin = approval.txOrigin;\n bytes32 transactionHash = approval.transactionHash;\n uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH,\n // approval.txOrigin,\n // approval.transactionHash,\n // keccak256(approval.transactionSignature)\n // approval.approvalExpirationTimeSeconds,\n // ));\n\n assembly {\n // Compute hash of transaction signature\n let transactionSignatureHash := keccak256(add(transactionSignature, 32), mload(transactionSignature))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), txOrigin) // txOrigin\n mstore(add(memPtr, 64), transactionHash) // transactionHash\n mstore(add(memPtr, 96), transactionSignatureHash) // transactionSignatureHash\n mstore(add(memPtr, 128), approvalExpirationTimeSeconds) // approvalExpirationTimeSeconds\n // Compute hash\n result := keccak256(memPtr, 160)\n }\n return result;\n }\n}\n", - "src/libs/LibEIP712Domain.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\n\nimport \"./LibConstants.sol\";\n\n\ncontract LibEIP712Domain is\n LibConstants\n{\n\n // EIP191 header for EIP712 prefix\n string constant internal EIP191_HEADER = \"\\x19\\x01\";\n\n // EIP712 Domain Name value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_NAME = \"0x Protocol Coordinator\";\n\n // EIP712 Domain Version value for the Coordinator\n string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = \"1.0.0\";\n\n // EIP712 Domain Name value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_NAME = \"0x Protocol\";\n\n // EIP712 Domain Version value for the Exchange\n string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = \"2\";\n\n // Hash of the EIP712 Domain Separator Schema\n bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(\n \"EIP712Domain(\",\n \"string name,\",\n \"string version,\",\n \"address verifyingContract\",\n \")\"\n ));\n\n // Hash of the EIP712 Domain Separator data for the Coordinator\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;\n\n // Hash of the EIP712 Domain Separator data for the Exchange\n // solhint-disable-next-line var-name-mixedcase\n bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;\n\n constructor ()\n public\n {\n EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)),\n keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)),\n uint256(address(this))\n ));\n\n EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked(\n EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)),\n keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)),\n uint256(address(EXCHANGE))\n ));\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of this contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to this EIP712 Domain.\n function hashEIP712CoordinatorMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain\n /// of the Exchange contract.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712ExchangeMessage(bytes32 hashStruct)\n internal\n view\n returns (bytes32 result)\n {\n return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct);\n }\n\n /// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.\n /// @param eip712DomainHash Hash of the domain domain separator data.\n /// @param hashStruct The EIP712 hash struct.\n /// @return EIP712 hash applied to the Exchange EIP712 Domain.\n function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)\n internal\n pure\n returns (bytes32 result)\n {\n // Assembly for more efficient computing:\n // keccak256(abi.encodePacked(\n // EIP191_HEADER,\n // EIP712_DOMAIN_HASH,\n // hashStruct\n // ));\n\n assembly {\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header\n mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash\n mstore(add(memPtr, 34), hashStruct) // Hash of struct\n\n // Compute hash\n result := keccak256(memPtr, 66)\n }\n return result;\n }\n}\n", - "src/libs/LibZeroExTransaction.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./LibEIP712Domain.sol\";\n\n\ncontract LibZeroExTransaction is\n LibEIP712Domain\n{\n // Hash for the EIP712 0x transaction schema\n // keccak256(abi.encodePacked(\n // \"ZeroExTransaction(\",\n // \"uint256 salt,\",\n // \"address signerAddress,\",\n // \"bytes data\",\n // \")\"\n // ));\n bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0x213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c;\n\n struct ZeroExTransaction {\n uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash.\n address signerAddress; // Address of transaction signer.\n bytes data; // AbiV2 encoded calldata.\n }\n\n /// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with the domain separator of this contract.\n function getTransactionHash(ZeroExTransaction memory transaction)\n public\n view\n returns (bytes32 transactionHash)\n {\n // Hash the transaction with the domain separator of the Exchange contract.\n transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction));\n return transactionHash;\n }\n\n /// @dev Calculates EIP712 hash of the 0x transaction with no domain separator.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @return EIP712 hash of the transaction with no domain separator.\n function hashZeroExTransaction(ZeroExTransaction memory transaction)\n internal\n pure\n returns (bytes32 result)\n {\n bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;\n bytes memory data = transaction.data;\n uint256 salt = transaction.salt;\n address signerAddress = transaction.signerAddress;\n\n // Assembly for more efficiently computing:\n // keccak256(abi.encodePacked(\n // EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,\n // transaction.salt,\n // uint256(transaction.signerAddress),\n // keccak256(transaction.data)\n // ));\n\n assembly {\n // Compute hash of data\n let dataHash := keccak256(add(data, 32), mload(data))\n\n // Load free memory pointer\n let memPtr := mload(64)\n\n mstore(memPtr, schemaHash) // hash of schema\n mstore(add(memPtr, 32), salt) // salt\n mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress\n mstore(add(memPtr, 96), dataHash) // hash of data\n\n // Compute hash\n result := keccak256(memPtr, 128)\n }\n return result;\n }\n}\n", - "src/mixins/MCoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../interfaces/ICoordinatorApprovalVerifier.sol\";\n\n\ncontract MCoordinatorApprovalVerifier is\n ICoordinatorApprovalVerifier\n{\n /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param orders Array of order structs containing order specifications.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.\n function assertValidTransactionOrdersApproval(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n LibOrder.Order[] memory orders,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n internal\n view;\n}\n", - "src/interfaces/ICoordinatorApprovalVerifier.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"@0x/contracts-exchange-libs/contracts/src/LibOrder.sol\";\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorApprovalVerifier {\n\n /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients\n /// that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function assertValidCoordinatorApprovals(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n view;\n\n /// @dev Decodes the orders from Exchange calldata representing any fill method.\n /// @param data Exchange calldata representing a fill method.\n /// @return The orders from the Exchange calldata.\n function decodeOrdersFromFillData(bytes memory data)\n public\n pure\n returns (LibOrder.Order[] memory orders);\n}\n", - "src/MixinCoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"./libs/LibZeroExTransaction.sol\";\nimport \"./libs/LibConstants.sol\";\nimport \"./mixins/MCoordinatorApprovalVerifier.sol\";\nimport \"./interfaces/ICoordinatorCore.sol\";\n\n\ncontract MixinCoordinatorCore is\n LibConstants,\n MCoordinatorApprovalVerifier,\n ICoordinatorCore\n{\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public\n {\n // Validate that the 0x transaction has been approves by each feeRecipient\n assertValidCoordinatorApprovals(\n transaction,\n txOrigin,\n transactionSignature,\n approvalExpirationTimeSeconds,\n approvalSignatures\n );\n\n // Execute the transaction\n EXCHANGE.executeTransaction(\n transaction.salt,\n transaction.signerAddress,\n transaction.data,\n transactionSignature\n );\n }\n}\n", - "src/interfaces/ICoordinatorCore.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.5;\npragma experimental \"ABIEncoderV2\";\n\nimport \"../libs/LibZeroExTransaction.sol\";\n\n\ncontract ICoordinatorCore {\n\n /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.\n /// @param transaction 0x transaction containing salt, signerAddress, and data.\n /// @param txOrigin Required signer of Ethereum transaction calling this function.\n /// @param transactionSignature Proof that the transaction has been signed by the signer.\n /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.\n /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.\n function executeTransaction(\n LibZeroExTransaction.ZeroExTransaction memory transaction,\n address txOrigin,\n bytes memory transactionSignature,\n uint256[] memory approvalExpirationTimeSeconds,\n bytes[] memory approvalSignatures\n )\n public;\n}\n" - }, "sourceTreeHashHex": "0xcd3a1dbf858b46a5820dab320baad978613f07ec73d35b6cbbde13c2937bbc04", - "compiler": { - "name": "solc", - "version": "soljson-v0.5.8+commit.23d335f2.js", - "settings": { - "optimizer": { - "enabled": true, - "runs": 1000000, - "details": { - "yul": true, - "deduplicate": true, - "cse": true, - "constantOptimizer": true - } - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode.object", - "evm.bytecode.sourceMap", - "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" - ] - } - }, - "evmVersion": "constantinople", - "remappings": [ - "@0x/contracts-utils=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-utils", - "@0x/contracts-exchange-libs=/Users/xianny/src/0x-monorepo/contracts/coordinator/node_modules/@0x/contracts-exchange-libs" - ] - } - }, "networks": {} -} \ No newline at end of file +} From cb3430e1cbb880011583df48c81ebd58815d3536 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 19:02:21 -0700 Subject: [PATCH 33/53] add Coordinator --- packages/monorepo-scripts/src/doc_gen_configs.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/monorepo-scripts/src/doc_gen_configs.ts b/packages/monorepo-scripts/src/doc_gen_configs.ts index 7a4e6bb2c3..97a7257f8d 100644 --- a/packages/monorepo-scripts/src/doc_gen_configs.ts +++ b/packages/monorepo-scripts/src/doc_gen_configs.ts @@ -38,6 +38,7 @@ export const docGenConfigs: DocGenConfigs = { // and getting confused. Any class name in this list will not have it's constructor rendered in our docs. CLASSES_WITH_HIDDEN_CONSTRUCTORS: [ 'AssetBuyer', + 'CoordinatorWrapper', 'DutchAuctionWrapper', 'ERC20ProxyWrapper', 'ERC20TokenWrapper', @@ -59,6 +60,8 @@ export const docGenConfigs: DocGenConfigs = { 'OrderError', 'AssetBuyerError', 'ForwarderWrapperError', + 'CoordinatorServerError', + 'CoordinatorServerCancellationResponse', ], // Some libraries only export types. In those cases, we cannot check if the exported types are part of the // "exported public interface". Thus we add them here and skip those checks. From e1d94819afb98136370f273e5599e29b1a9b97b0 Mon Sep 17 00:00:00 2001 From: xianny Date: Wed, 8 May 2019 19:29:09 -0700 Subject: [PATCH 34/53] add exports --- packages/contract-wrappers/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 2aee5fb863..1cb77bfb69 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -75,6 +75,8 @@ export { Order, SignedOrder, AssetProxyId, + SignedZeroExTransaction, + ZeroExTransaction, } from '@0x/types'; export { From 2564554f3f1691ccee8f61f861ba3198976365c9 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 07:10:23 -0700 Subject: [PATCH 35/53] add cacheing, add non-coordinator-order test --- .../contract_wrappers/coordinator_wrapper.ts | 25 +++++++---- .../test/coordinator_wrapper_test.ts | 45 ++++++++++++++----- packages/fill-scenarios/src/fill_scenarios.ts | 11 ++--- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index ca0b964bc6..176dbc811c 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -40,6 +40,7 @@ export class CoordinatorWrapper extends ContractWrapper { private readonly _registryInstance: CoordinatorRegistryContract; private readonly _exchangeInstance: ExchangeContract; private readonly _transactionEncoder: TransactionEncoder; + private readonly _feeRecipientToEndpoint: { [feeRecipient: string]: string } = {}; /** * Instantiate CoordinatorWrapper @@ -713,17 +714,23 @@ export class CoordinatorWrapper extends ContractWrapper { } private async _getServerEndpointOrThrowAsync(feeRecipientAddress: string): Promise { - const coordinatorOperatorEndpoint = await this._registryInstance.getCoordinatorEndpoint.callAsync( - feeRecipientAddress, - ); - if (coordinatorOperatorEndpoint === '') { - throw new Error( - `No Coordinator server endpoint found in Coordinator Registry for feeRecipientAddress: ${feeRecipientAddress}. Registry contract address: ${ - this.registryAddress - }`, + const cached = this._feeRecipientToEndpoint[feeRecipientAddress]; + const endpoint = cached !== undefined ? cached : await _fetchServerEndpointOrThrowAsync(feeRecipientAddress, this._registryInstance); + return endpoint; + + async function _fetchServerEndpointOrThrowAsync(feeRecipient: string, registryInstance: CoordinatorRegistryContract): Promise { + const coordinatorOperatorEndpoint = await registryInstance.getCoordinatorEndpoint.callAsync( + feeRecipient, ); + if (coordinatorOperatorEndpoint === '' || coordinatorOperatorEndpoint === undefined) { + throw new Error( + `No Coordinator server endpoint found in Coordinator Registry for feeRecipientAddress: ${feeRecipient}. Registry contract address: ${ + registryInstance.address + }`, + ); + } + return coordinatorOperatorEndpoint; } - return coordinatorOperatorEndpoint; } private async _generateSignedZeroExTransactionAsync( diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 1eaf2cf7ce..1df0613f21 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -28,7 +28,7 @@ const anotherCoordinatorPort = '4000'; const coordinatorEndpoint = 'http://localhost:'; // tslint:disable:custom-no-magic-numbers -describe('CoordinatorWrapper', () => { +describe.only('CoordinatorWrapper', () => { const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); let coordinatorServerApp: http.Server; @@ -80,7 +80,6 @@ describe('CoordinatorWrapper', () => { exchangeContractAddress, contractWrappers.erc20Proxy.address, contractWrappers.erc721Proxy.address, - contractAddresses.coordinator, ); [ , @@ -205,6 +204,7 @@ describe('CoordinatorWrapper', () => { }); beforeEach(async () => { await blockchainLifecycle.startAsync(); + signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( makerAssetData, takerAssetData, @@ -214,6 +214,8 @@ describe('CoordinatorWrapper', () => { takerAddress, fillableAmount, feeRecipientAddressOne, + undefined, + contractWrappers.coordinator.address, ); anotherSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( makerAssetData, @@ -224,6 +226,8 @@ describe('CoordinatorWrapper', () => { takerAddress, fillableAmount, feeRecipientAddressOne, + undefined, + contractWrappers.coordinator.address, ); signedOrderWithDifferentFeeRecipient = await fillScenarios.createFillableSignedOrderWithFeesAsync( makerAssetData, @@ -234,6 +238,8 @@ describe('CoordinatorWrapper', () => { takerAddress, fillableAmount, feeRecipientAddressTwo, + undefined, + contractWrappers.coordinator.address, ); signedOrderWithDifferentCoordinatorOperator = await fillScenarios.createFillableSignedOrderWithFeesAsync( makerAssetData, @@ -244,6 +250,8 @@ describe('CoordinatorWrapper', () => { takerAddress, fillableAmount, feeRecipientAddressThree, + undefined, + contractWrappers.coordinator.address, ); }); afterEach(async () => { @@ -286,7 +294,7 @@ describe('CoordinatorWrapper', () => { describe('#batchFillOrdersAsync', () => { it('should fill a batch of valid orders', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; + const takerAssetFillAmounts = Array(2).fill(takerTokenFillAmount); txHash = await contractWrappers.coordinator.batchFillOrdersAsync( signedOrders, takerAssetFillAmounts, @@ -297,7 +305,7 @@ describe('CoordinatorWrapper', () => { }); it('should fill a batch of orders with different feeRecipientAddresses with the same coordinator server', async () => { const signedOrders = [signedOrder, anotherSignedOrder, signedOrderWithDifferentFeeRecipient]; - const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; + const takerAssetFillAmounts = Array(3).fill(takerTokenFillAmount); txHash = await contractWrappers.coordinator.batchFillOrdersAsync( signedOrders, takerAssetFillAmounts, @@ -316,12 +324,7 @@ describe('CoordinatorWrapper', () => { signedOrderWithDifferentFeeRecipient, signedOrderWithDifferentCoordinatorOperator, ]; - const takerAssetFillAmounts = [ - takerTokenFillAmount, - takerTokenFillAmount, - takerTokenFillAmount, - takerTokenFillAmount, - ]; + const takerAssetFillAmounts = Array(4).fill(takerTokenFillAmount); txHash = await contractWrappers.coordinator.batchFillOrdersAsync( signedOrders, takerAssetFillAmounts, @@ -330,6 +333,28 @@ describe('CoordinatorWrapper', () => { await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); + + it('should fill a batch of mixed coordinator and non-coordinator orders', async () => { + const nonCoordinatorOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerAssetData, + takerAssetData, + new BigNumber(1), + new BigNumber(1), + makerAddress, + takerAddress, + fillableAmount, + feeRecipientAddressOne, + undefined, + ); + const signedOrders = [signedOrder, nonCoordinatorOrder]; + const takerAssetFillAmounts = Array(2).fill(takerTokenFillAmount); + txHash = await contractWrappers.coordinator.batchFillOrdersAsync( + signedOrders, + takerAssetFillAmounts, + takerAddress, + ); + await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + }); }); }); describe('soft cancel order(s)', () => { diff --git a/packages/fill-scenarios/src/fill_scenarios.ts b/packages/fill-scenarios/src/fill_scenarios.ts index 7ba5f25b15..4d5597885b 100644 --- a/packages/fill-scenarios/src/fill_scenarios.ts +++ b/packages/fill-scenarios/src/fill_scenarios.ts @@ -18,7 +18,6 @@ export class FillScenarios { private readonly _exchangeAddress: string; private readonly _erc20ProxyAddress: string; private readonly _erc721ProxyAddress: string; - private readonly _senderAddress?: string; constructor( supportedProvider: SupportedProvider, userAddresses: string[], @@ -26,7 +25,6 @@ export class FillScenarios { exchangeAddress: string, erc20ProxyAddress: string, erc721ProxyAddress: string, - senderAddress?: string, ) { this._web3Wrapper = new Web3Wrapper(supportedProvider); this._userAddresses = userAddresses; @@ -35,7 +33,6 @@ export class FillScenarios { this._exchangeAddress = exchangeAddress; this._erc20ProxyAddress = erc20ProxyAddress; this._erc721ProxyAddress = erc721ProxyAddress; - this._senderAddress = senderAddress; } public async createFillableSignedOrderAsync( makerAssetData: string, @@ -65,6 +62,7 @@ export class FillScenarios { fillableAmount: BigNumber, feeRecipientAddress: string, expirationTimeSeconds?: BigNumber, + senderAddress?: string, ): Promise { return this._createAsymmetricFillableSignedOrderWithFeesAsync( makerAssetData, @@ -77,6 +75,7 @@ export class FillScenarios { fillableAmount, feeRecipientAddress, expirationTimeSeconds, + senderAddress, ); } public async createAsymmetricFillableSignedOrderAsync( @@ -152,6 +151,7 @@ export class FillScenarios { takerFillableAmount: BigNumber, feeRecipientAddress: string, expirationTimeSeconds?: BigNumber, + senderAddress?: string, ): Promise { await this._increaseBalanceAndAllowanceWithAssetDataAsync(makerAssetData, makerAddress, makerFillableAmount); await this._increaseBalanceAndAllowanceWithAssetDataAsync(takerAssetData, takerAddress, takerFillableAmount); @@ -160,7 +160,8 @@ export class FillScenarios { this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee), this._increaseERC20BalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee), ]); - const senderAddress = this._senderAddress; + const _senderAddress = senderAddress ? senderAddress : constants.NULL_ADDRESS; + const signedOrder = await orderFactory.createSignedOrderAsync( this._web3Wrapper.getProvider(), makerAddress, @@ -171,7 +172,7 @@ export class FillScenarios { this._exchangeAddress, { takerAddress, - senderAddress, + senderAddress: _senderAddress, makerFee, takerFee, feeRecipientAddress, From 62593fb06f1dddb617e992e193daccae5603f237 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 07:14:27 -0700 Subject: [PATCH 36/53] change OrderError -> TypedDataError --- packages/order-utils/CHANGELOG.json | 9 +++++++++ packages/order-utils/src/index.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index fe19ba8c23..49d7c7a6a9 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "8.0.0", + "changes": [ + { + "note": "Renamed `OrderError` to `TypedDataError`", + "pr": 1792 + } + ] + }, { "version": "7.2.0", "changes": [ diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 05d5d1976c..e22cf09236 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -68,7 +68,7 @@ export { } from '@0x/types'; export { - TypedDataError as OrderError, + TypedDataError, TradeSide, TransferType, FindFeeOrdersThatCoverFeesForTargetOrdersOpts, From f349c6d1d8da5cb7b268ec77262b86e3f4f2a6d6 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 07:41:34 -0700 Subject: [PATCH 37/53] tweaks after review --- packages/contract-wrappers/CHANGELOG.json | 9 ++++ packages/contract-wrappers/package.json | 2 + .../contract_wrappers/coordinator_wrapper.ts | 18 +++---- packages/order-utils/src/signature_utils.ts | 8 +-- yarn.lock | 51 +++++-------------- 5 files changed, 34 insertions(+), 54 deletions(-) diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index d50ece68f3..a7f4195cd9 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "9.1.0", + "changes": [ + { + "note": "Added CoordinatorWrapper to support orders with the Coordinator extension contract", + "pr": 1792 + } + ] + }, { "version": "9.0.0", "changes": [ diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 7b30781da7..67a6f1434b 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -81,6 +81,7 @@ "@0x/typescript-typings": "^4.2.2", "@0x/utils": "^4.3.1", "@0x/web3-wrapper": "^6.0.5", + "@types/ramda": "^0.26.8", "ethereum-types": "^2.1.2", "ethereumjs-abi": "0.6.5", "ethereumjs-blockstream": "6.0.0", @@ -89,6 +90,7 @@ "http-status-codes": "^1.3.2", "js-sha3": "^0.7.0", "lodash": "^4.17.11", + "ramda": "^0.26.1", "uuid": "^3.3.2" }, "publishConfig": { diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 176dbc811c..2aa114be56 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -8,7 +8,7 @@ import { BigNumber, fetchAsync } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { ContractAbi } from 'ethereum-types'; import * as HttpStatus from 'http-status-codes'; -import * as _ from 'lodash'; +import flatten from 'ramda/src/flatten'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; @@ -656,8 +656,8 @@ export class CoordinatorWrapper extends ContractWrapper { formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse), ); - const allSignatures = allApprovals.map(a => a.signatures).reduce(flatten, []); - const allExpirationTimes = allApprovals.map(a => a.expirationTimeSeconds).reduce(flatten, []); + const allSignatures = flatten(allApprovals.map(a => a.signatures)); + const allExpirationTimes = flatten(allApprovals.map(a => a.expirationTimeSeconds)); // submit transaction with approvals const txHash = await this._submitCoordinatorTransactionAsync( @@ -673,14 +673,13 @@ export class CoordinatorWrapper extends ContractWrapper { // format errors and approvals // concatenate approvals const notCoordinatorOrders = signedOrders.filter(o => o.senderAddress !== this.address); - const approvedOrders = approvalResponses + const approvedOrdersNested = approvalResponses .map(resp => { const endpoint = resp.coordinatorOperator; const orders = serverEndpointsToOrders[endpoint]; return orders; - }) - .reduce(flatten, []) - .concat(notCoordinatorOrders); + }); + const approvedOrders = flatten(approvedOrdersNested.concat(notCoordinatorOrders)); // lookup orders with errors const errorsWithOrders = errorResponses.map(resp => { @@ -855,8 +854,5 @@ function getMakerAddressOrThrow(orders: Array): string { } return orders[0].makerAddress; } -function flatten(acc: T[], val: T | T[]): T[] { - acc.push(...val); - return acc; -} + // tslint:disable:max-file-line-count diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 87dc66bfbd..bc393f3cf7 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -293,12 +293,12 @@ export const signatureUtils = { } }, /** - * Signs an order using `eth_signTypedData` and returns a SignedOrder. + * Signs a ZeroExTransaction using `eth_signTypedData` and returns a SignedZeroExTransaction. * @param supportedProvider Web3 provider to use for all JSON RPC requests - * @param transaction The ZeroEx Transaction to sign. - * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address + * @param transaction The ZeroEx Transaction to sign. + * @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address * must be available via the supplied Provider. - * @return A SignedOrder containing the order and Elliptic curve signature with Signature Type. + * @return A SignedZeroExTransaction containing the ZeroExTransaction and Elliptic curve signature with Signature Type. */ async ecSignTypedDataTransactionAsync( supportedProvider: SupportedProvider, diff --git a/yarn.lock b/yarn.lock index c4547c628c..e7e71c0d52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1556,13 +1556,6 @@ dependencies: "@types/node" "*" -"@types/eth-sig-util@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@types/eth-sig-util/-/eth-sig-util-2.1.0.tgz#54497e9c01b5ee3a60475686cce1a20ddccc358b" - integrity sha512-GWX0s/FFGWl6lO2nbd9nq3fh1x47vmLL/p4yDG1+VgCqrip1ErQrbHlTZThtEc6JrcmwCKB2H1de32Hdo3JdJg== - dependencies: - "@types/node" "*" - "@types/ethereum-protocol@*": version "1.0.0" resolved "https://registry.npmjs.org/@types/ethereum-protocol/-/ethereum-protocol-1.0.0.tgz#416e3827d5fdfa4658b0045b35a008747871b271" @@ -1771,6 +1764,11 @@ version "0.25.46" resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.25.46.tgz#8399a35eb117f4a821deb9c4cfecc9b276fb7daf" +"@types/ramda@^0.26.8": + version "0.26.8" + resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.26.8.tgz#e002612cca52e52f9176d577f4d6229c8c72a10a" + integrity sha512-PSMkNNhB900U2xcyndlkVjJeCXpVtf1yod0Kdq/ArsLDIE0tW8pLBChmQeJs4o4dfp3AEP+AGm6zIseZPU4ndA== + "@types/rc-slider@^8.6.0": version "8.6.0" resolved "https://registry.yarnpkg.com/@types/rc-slider/-/rc-slider-8.6.0.tgz#7f061a920b067825c8455cf481c57b0927889c72" @@ -4025,7 +4023,7 @@ buffer@^5.0.3, buffer@^5.0.5: base64-js "^1.0.2" ieee754 "^1.1.4" -buffer@^5.1.0, buffer@^5.2.1: +buffer@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" dependencies: @@ -6621,18 +6619,6 @@ eth-sig-util@^1.4.2: ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" ethereumjs-util "^5.1.1" -eth-sig-util@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-2.1.2.tgz#9b357395b5ca07fae6b430d3e534cf0a0f1df118" - integrity sha512-bNgt7txkEmaNlLf+PrbwYIdp4KRkB3E7hW0/QwlBpgv920pVVyQnF0evoovfiRveNKM4OrtPYZTojjmsfuCUOw== - dependencies: - buffer "^5.2.1" - elliptic "^6.4.0" - ethereumjs-abi "0.6.5" - ethereumjs-util "^5.1.1" - tweetnacl "^1.0.0" - tweetnacl-util "^0.15.0" - eth-tx-summary@^3.1.2: version "3.2.1" resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.1.tgz#0c2d5e4c57d2511614f85b9b583c32fa2924166c" @@ -10958,9 +10944,10 @@ lodash.words@^3.0.0: dependencies: lodash._root "^3.0.0" -lodash@4.17.11, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.3: +lodash@4.17.11, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.3: version "4.17.11" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== lodash@=4.17.4: version "4.17.4" @@ -10978,11 +10965,6 @@ lodash@^4.17.10: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" -lodash@^4.17.11: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - lodash@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" @@ -13793,9 +13775,10 @@ ramda@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" -ramda@^0.26: +ramda@^0.26, ramda@^0.26.1: version "0.26.1" - resolved "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" + integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ== randexp@0.4.6: version "0.4.6" @@ -16907,11 +16890,6 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tweetnacl-util@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.0.tgz#4576c1cee5e2d63d207fee52f1ba02819480bc75" - integrity sha1-RXbBzuXi1j0gf+5S8boCgZSAvHU= - tweetnacl@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.13.2.tgz#453161770469d45cd266c36404e2bc99a8fa9944" @@ -16920,11 +16898,6 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" -tweetnacl@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.1.tgz#2594d42da73cd036bd0d2a54683dd35a6b55ca17" - integrity sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A== - type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" From 835c38f3171b11366d8dd8671b437b2a24b1d585 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 08:00:08 -0700 Subject: [PATCH 38/53] format doc comments --- .../contract_wrappers/coordinator_wrapper.ts | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 2aa114be56..942740d663 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -178,9 +178,8 @@ export class CoordinatorWrapper extends ContractWrapper { /** * Batch version of fillOrderAsync. Executes multiple fills atomically in a single transaction. - * Under-the-hood, this - * method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints registered in the - * coordinator registry contract. It requests a signature from each coordinator server before + * Under-the-hood, this method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints + * registered in the coordinator registry contract. It requests a signature from each coordinator server before * submitting the orders and signatures as a 0x transaction to the coordinator extension contract, which validates the * signatures and then fills the order through the Exchange contract. * If any `feeRecipientAddress` in the batch is not registered to a coordinator server, the whole batch fails. @@ -271,9 +270,8 @@ export class CoordinatorWrapper extends ContractWrapper { /** * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. - * Under-the-hood, this - * method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints registered in the - * coordinator registry contract. It requests a signature from each coordinator server before + * Under-the-hood, this method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints + * registered in the coordinator registry contract. It requests a signature from each coordinator server before * submitting the orders and signatures as a 0x transaction to the coordinator extension contract, which validates the * signatures and then fills the order through the Exchange contract. * If any `feeRecipientAddress` in the batch is not registered to a coordinator server, the whole batch fails. @@ -304,9 +302,8 @@ export class CoordinatorWrapper extends ContractWrapper { /** * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. - * Under-the-hood, this - * method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints registered in the - * coordinator registry contract. It requests a signature from each coordinator server before + * Under-the-hood, this method uses the `feeRecipientAddress`s of the orders to looks up the coordinator server endpoints + * registered in the coordinator registry contract. It requests a signature from each coordinator server before * submitting the orders and signatures as a 0x transaction to the coordinator extension contract, which validates the * signatures and then fills the order through the Exchange contract. * If any `feeRecipientAddress` in the batch is not registered to a coordinator server, the whole batch fails. @@ -390,7 +387,9 @@ export class CoordinatorWrapper extends ContractWrapper { } /** - * Soft cancel a given order. See [soft cancels](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#soft-cancels). + * Soft cancel a given order. + * Soft cancels are recorded only on coordinator operator servers and do not involve an Ethereum transaction. + * See [soft cancels](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#soft-cancels). * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. * @return CoordinatorServerCancellationResponse. See [Cancellation Response](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/coordinator-specification.md#response). */ @@ -438,7 +437,6 @@ export class CoordinatorWrapper extends ContractWrapper { const serverEndpointsToOrders = await this._mapServerEndpointsToOrdersAsync(orders); // make server requests - let numErrors = 0; const errorResponses: CoordinatorServerResponse[] = []; const successResponses: CoordinatorServerCancellationResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); @@ -446,14 +444,13 @@ export class CoordinatorWrapper extends ContractWrapper { const response = await this._executeServerRequestAsync(transaction, makerAddress, endpoint); if (response.isError) { errorResponses.push(response); - numErrors++; } else { successResponses.push(response.body as CoordinatorServerCancellationResponse); } } // if no errors - if (numErrors === 0) { + if (errorResponses.length === 0) { return successResponses; } else { // lookup orders with errors @@ -635,7 +632,6 @@ export class CoordinatorWrapper extends ContractWrapper { const serverEndpointsToOrders = await this._mapServerEndpointsToOrdersAsync(coordinatorOrders); // make server requests - let numErrors = 0; const errorResponses: CoordinatorServerResponse[] = []; const approvalResponses: CoordinatorServerResponse[] = []; const transaction = await this._generateSignedZeroExTransactionAsync(data, takerAddress); @@ -643,14 +639,13 @@ export class CoordinatorWrapper extends ContractWrapper { const response = await this._executeServerRequestAsync(transaction, takerAddress, endpoint); if (response.isError) { errorResponses.push(response); - numErrors++; } else { approvalResponses.push(response); } } // if no errors - if (numErrors === 0) { + if (errorResponses.length === 0) { // concatenate all approval responses const allApprovals = approvalResponses.map(resp => formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse), @@ -673,12 +668,11 @@ export class CoordinatorWrapper extends ContractWrapper { // format errors and approvals // concatenate approvals const notCoordinatorOrders = signedOrders.filter(o => o.senderAddress !== this.address); - const approvedOrdersNested = approvalResponses - .map(resp => { - const endpoint = resp.coordinatorOperator; - const orders = serverEndpointsToOrders[endpoint]; - return orders; - }); + const approvedOrdersNested = approvalResponses.map(resp => { + const endpoint = resp.coordinatorOperator; + const orders = serverEndpointsToOrders[endpoint]; + return orders; + }); const approvedOrders = flatten(approvedOrdersNested.concat(notCoordinatorOrders)); // lookup orders with errors @@ -714,13 +708,17 @@ export class CoordinatorWrapper extends ContractWrapper { private async _getServerEndpointOrThrowAsync(feeRecipientAddress: string): Promise { const cached = this._feeRecipientToEndpoint[feeRecipientAddress]; - const endpoint = cached !== undefined ? cached : await _fetchServerEndpointOrThrowAsync(feeRecipientAddress, this._registryInstance); + const endpoint = + cached !== undefined + ? cached + : await _fetchServerEndpointOrThrowAsync(feeRecipientAddress, this._registryInstance); return endpoint; - async function _fetchServerEndpointOrThrowAsync(feeRecipient: string, registryInstance: CoordinatorRegistryContract): Promise { - const coordinatorOperatorEndpoint = await registryInstance.getCoordinatorEndpoint.callAsync( - feeRecipient, - ); + async function _fetchServerEndpointOrThrowAsync( + feeRecipient: string, + registryInstance: CoordinatorRegistryContract, + ): Promise { + const coordinatorOperatorEndpoint = await registryInstance.getCoordinatorEndpoint.callAsync(feeRecipient); if (coordinatorOperatorEndpoint === '' || coordinatorOperatorEndpoint === undefined) { throw new Error( `No Coordinator server endpoint found in Coordinator Registry for feeRecipientAddress: ${feeRecipient}. Registry contract address: ${ From 0960ec631ab822e10e7a3f8c9c5ae291f1e2d44a Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 08:01:52 -0700 Subject: [PATCH 39/53] replace OrderError -> TypedDataError everywhere --- packages/monorepo-scripts/src/doc_gen_configs.ts | 2 +- packages/website/ts/utils/utils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/monorepo-scripts/src/doc_gen_configs.ts b/packages/monorepo-scripts/src/doc_gen_configs.ts index 97a7257f8d..68c07dbb22 100644 --- a/packages/monorepo-scripts/src/doc_gen_configs.ts +++ b/packages/monorepo-scripts/src/doc_gen_configs.ts @@ -57,7 +57,7 @@ export const docGenConfigs: DocGenConfigs = { 'NonceSubproviderErrors', 'Web3WrapperErrors', 'ContractWrappersError', - 'OrderError', + 'TypedDataError', 'AssetBuyerError', 'ForwarderWrapperError', 'CoordinatorServerError', diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts index bdd7afa199..5944e34c6b 100644 --- a/packages/website/ts/utils/utils.ts +++ b/packages/website/ts/utils/utils.ts @@ -1,5 +1,5 @@ import { ContractWrappersError } from '@0x/contract-wrappers'; -import { assetDataUtils, OrderError } from '@0x/order-utils'; +import { assetDataUtils, TypedDataError } from '@0x/order-utils'; import { constants as sharedConstants, Networks } from '@0x/react-shared'; import { ExchangeContractErrs } from '@0x/types'; import { BigNumber } from '@0x/utils'; @@ -232,7 +232,7 @@ export const utils = { zeroExErrToHumanReadableErrMsg(error: ContractWrappersError | ExchangeContractErrs, takerAddress: string): string { const ContractWrappersErrorToHumanReadableError: { [error: string]: string } = { [BlockchainCallErrs.UserHasNoAssociatedAddresses]: 'User has no addresses available', - [OrderError.InvalidSignature]: 'Order signature is not valid', + [TypedDataError.InvalidSignature]: 'Order signature is not valid', [ContractWrappersError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network', [ContractWrappersError.InvalidJump]: 'Invalid jump occured while executing the transaction', [ContractWrappersError.OutOfGas]: 'Transaction ran out of gas', From 0e664ff89b56b0edb66f8f7346b88b12af94fb33 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 08:55:07 -0700 Subject: [PATCH 40/53] fix flatten --- .../src/contract_wrappers/coordinator_wrapper.ts | 2 +- packages/pipeline/package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 942740d663..952764259d 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -8,7 +8,7 @@ import { BigNumber, fetchAsync } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { ContractAbi } from 'ethereum-types'; import * as HttpStatus from 'http-status-codes'; -import flatten from 'ramda/src/flatten'; +import { flatten } from 'ramda'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; diff --git a/packages/pipeline/package.json b/packages/pipeline/package.json index dafa96c795..bfd9468d27 100644 --- a/packages/pipeline/package.json +++ b/packages/pipeline/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@0x/tslint-config": "^3.0.1", "@types/axios": "^0.14.0", - "@types/ramda": "^0.25.38", + "@types/ramda": "^0.26.8", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", @@ -60,7 +60,7 @@ "ethereum-types": "^2.1.2", "pg": "^7.5.0", "prettier": "^1.16.3", - "ramda": "^0.25.0", + "ramda": "^0.26.1", "reflect-metadata": "^0.1.12", "sqlite3": "^4.0.2", "typeorm": "0.2.7" From 0e21f380ba130b1d874d59b10998e8a541918db8 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 09:27:59 -0700 Subject: [PATCH 41/53] simplify function --- .../src/scripts/pull_radar_relay_orders.ts | 12 +-------- yarn.lock | 27 +------------------ 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/packages/pipeline/src/scripts/pull_radar_relay_orders.ts b/packages/pipeline/src/scripts/pull_radar_relay_orders.ts index 8e87208039..d032ab4880 100644 --- a/packages/pipeline/src/scripts/pull_radar_relay_orders.ts +++ b/packages/pipeline/src/scripts/pull_radar_relay_orders.ts @@ -32,7 +32,7 @@ async function getOrderbookAsync(): Promise { // Parse the sra orders, then add source url to each. const orders = R.pipe( parseSraOrders, - R.map(setSourceUrl(RADAR_RELAY_URL)), + R.map(o => R.set(sourceUrlProp, RADAR_RELAY_URL, o)), )(rawOrders); // Save all the orders and update the observed time stamps in a single // transaction. @@ -50,13 +50,3 @@ async function getOrderbookAsync(): Promise { } const sourceUrlProp = R.lensProp('sourceUrl'); - -/** - * Sets the source url for a single order. Returns a new order instead of - * mutating the given one. - */ -const setSourceUrl = R.curry( - (sourceURL: string, order: SraOrder): SraOrder => { - return R.set(sourceUrlProp, sourceURL, order); - }, -); diff --git a/yarn.lock b/yarn.lock index e7e71c0d52..b0f7196d12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1760,10 +1760,6 @@ version "5.1.0" resolved "https://registry.yarnpkg.com/@types/query-string/-/query-string-5.1.0.tgz#7f40cdea49ddafa0ea4f3db35fb6c24d3bfd4dcc" -"@types/ramda@^0.25.38": - version "0.25.46" - resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.25.46.tgz#8399a35eb117f4a821deb9c4cfecc9b276fb7daf" - "@types/ramda@^0.26.8": version "0.26.8" resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.26.8.tgz#e002612cca52e52f9176d577f4d6229c8c72a10a" @@ -8248,23 +8244,11 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - integrity sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg= - dependencies: - natives "^1.1.0" - -graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@4.1.15, graceful-fs@^3.0.0, graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~1.2.0: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== -graceful-fs@~1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - integrity sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q= - "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -11726,11 +11710,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -natives@^1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.6.tgz#a603b4a498ab77173612b9ea1acdec4d980f00bb" - integrity sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -13771,10 +13750,6 @@ ramda@0.21.0: version "0.21.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" -ramda@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" - ramda@^0.26, ramda@^0.26.1: version "0.26.1" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" From be4d1fda4cb87f8ca2adf4a8bb529dff09b77ba2 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 10:10:29 -0700 Subject: [PATCH 42/53] bump circleci From 3f27ea44f8ad42d8b4e7bebc2af95d4f76a0ae57 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 10:12:22 -0700 Subject: [PATCH 43/53] remove `only` flag --- packages/contract-wrappers/test/coordinator_wrapper_test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 1df0613f21..72afd3dba5 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -28,7 +28,7 @@ const anotherCoordinatorPort = '4000'; const coordinatorEndpoint = 'http://localhost:'; // tslint:disable:custom-no-magic-numbers -describe.only('CoordinatorWrapper', () => { +describe('CoordinatorWrapper', () => { const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); let coordinatorServerApp: http.Server; From be94f2a914c6e74be6c3cc64737422b54cc95b7b Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 11:10:39 -0700 Subject: [PATCH 44/53] try increasing node max-old-space-size --- packages/monorepo-scripts/src/test_installation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 64d60e0103..4a3d65818d 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -137,7 +137,7 @@ async function testInstallPackageAsync( await writeFileAsync(tsconfigFilePath, JSON.stringify(tsConfig, null, '\t')); utils.log(`Compiling ${packageName}`); const tscBinaryPath = path.join(monorepoRootPath, './node_modules/typescript/bin/tsc'); - await execAsync(tscBinaryPath, { cwd: testDirectory }); + await execAsync(`node --max-old-space-size=4096 ${tscBinaryPath}`, { cwd: testDirectory }); utils.log(`Successfully compiled with ${packageName} as a dependency`); const isUnrunnablePkg = _.includes(UNRUNNABLE_PACKAGES, packageName); if (!isUnrunnablePkg) { From e09b60c222503e2daf1c41a3a421bf94155992b0 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 11:45:00 -0700 Subject: [PATCH 45/53] try reducing chunk size --- packages/monorepo-scripts/src/test_installation.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 4a3d65818d..4ac3ae27fb 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -55,7 +55,7 @@ function logIfDefined(x: any): void { packages, pkg => !pkg.packageJson.private && pkg.packageJson.main !== undefined && pkg.packageJson.main.endsWith('.js'), ); - const CHUNK_SIZE = 15; + const CHUNK_SIZE = 12; const chunkedInstallablePackages = _.chunk(installablePackages, CHUNK_SIZE); utils.log(`Testing all packages in ${chunkedInstallablePackages.length} chunks`); for (const installablePackagesChunk of chunkedInstallablePackages) { @@ -137,7 +137,7 @@ async function testInstallPackageAsync( await writeFileAsync(tsconfigFilePath, JSON.stringify(tsConfig, null, '\t')); utils.log(`Compiling ${packageName}`); const tscBinaryPath = path.join(monorepoRootPath, './node_modules/typescript/bin/tsc'); - await execAsync(`node --max-old-space-size=4096 ${tscBinaryPath}`, { cwd: testDirectory }); + await execAsync(tscBinaryPath, { cwd: testDirectory }); utils.log(`Successfully compiled with ${packageName} as a dependency`); const isUnrunnablePkg = _.includes(UNRUNNABLE_PACKAGES, packageName); if (!isUnrunnablePkg) { From 5fbb3b2fb3c3ff6c27fdea3453e1ede110a8c52d Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 12:27:49 -0700 Subject: [PATCH 46/53] real small chunk size --- packages/monorepo-scripts/src/test_installation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 4ac3ae27fb..70fddb1711 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -55,7 +55,7 @@ function logIfDefined(x: any): void { packages, pkg => !pkg.packageJson.private && pkg.packageJson.main !== undefined && pkg.packageJson.main.endsWith('.js'), ); - const CHUNK_SIZE = 12; + const CHUNK_SIZE = 5; const chunkedInstallablePackages = _.chunk(installablePackages, CHUNK_SIZE); utils.log(`Testing all packages in ${chunkedInstallablePackages.length} chunks`); for (const installablePackagesChunk of chunkedInstallablePackages) { From 6e040111cb38c528692d58181bc72e5823931878 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 12:36:50 -0700 Subject: [PATCH 47/53] compile only contract-wrappers --- packages/monorepo-scripts/src/test_installation.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 70fddb1711..0616b06cc8 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -55,8 +55,9 @@ function logIfDefined(x: any): void { packages, pkg => !pkg.packageJson.private && pkg.packageJson.main !== undefined && pkg.packageJson.main.endsWith('.js'), ); - const CHUNK_SIZE = 5; - const chunkedInstallablePackages = _.chunk(installablePackages, CHUNK_SIZE); + const CHUNK_SIZE = 15; + // const chunkedInstallablePackages = _.chunk(installablePackages, CHUNK_SIZE); + const chunkedInstallablePackages = [installablePackages.filter(p => p.packageJson.name === '@0x/contract-wrappers')]; utils.log(`Testing all packages in ${chunkedInstallablePackages.length} chunks`); for (const installablePackagesChunk of chunkedInstallablePackages) { utils.log('Testing packages:'); From 34617092186ae6946307a6cc6cb31802cb027366 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 12:55:04 -0700 Subject: [PATCH 48/53] remove changelog --- packages/contract-wrappers/CHANGELOG.json | 9 --------- packages/monorepo-scripts/src/test_installation.ts | 3 +-- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index a7f4195cd9..d50ece68f3 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,13 +1,4 @@ [ - { - "version": "9.1.0", - "changes": [ - { - "note": "Added CoordinatorWrapper to support orders with the Coordinator extension contract", - "pr": 1792 - } - ] - }, { "version": "9.0.0", "changes": [ diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 0616b06cc8..64d60e0103 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -56,8 +56,7 @@ function logIfDefined(x: any): void { pkg => !pkg.packageJson.private && pkg.packageJson.main !== undefined && pkg.packageJson.main.endsWith('.js'), ); const CHUNK_SIZE = 15; - // const chunkedInstallablePackages = _.chunk(installablePackages, CHUNK_SIZE); - const chunkedInstallablePackages = [installablePackages.filter(p => p.packageJson.name === '@0x/contract-wrappers')]; + const chunkedInstallablePackages = _.chunk(installablePackages, CHUNK_SIZE); utils.log(`Testing all packages in ${chunkedInstallablePackages.length} chunks`); for (const installablePackagesChunk of chunkedInstallablePackages) { utils.log('Testing packages:'); From cb3ae416365514c0101da469c108508de9f9a083 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 12:56:52 -0700 Subject: [PATCH 49/53] temporarily skip other circle jobs --- .circleci/config.yml | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ea23a41849..076a4ab7ec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -393,39 +393,39 @@ workflows: main: jobs: - build - - build-website: - requires: - - build - - test-contracts-ganache: - requires: - - build + # - build-website: + # requires: + # - build + # - test-contracts-ganache: + # requires: + # - build # TODO(albrow): Tests always fail on Geth right now because our fork # is outdated. Uncomment once we have updated our Geth fork. # - test-contracts-geth: # requires: # - build - - test-pipeline: - requires: - - build - - test-rest: - requires: - - build - - static-tests: - requires: - - build + # - test-pipeline: + # requires: + # - build + # - test-rest: + # requires: + # - build + # - static-tests: + # requires: + # - build - test-publish: requires: - build - - test-doc-generation: - requires: - - build - - submit-coverage: - requires: - - test-rest - - test-python - - static-tests-python: - requires: - - test-python - - test-python + # - test-doc-generation: + # requires: + # - build + # - submit-coverage: + # requires: + # - test-rest + # - test-python + # - static-tests-python: + # requires: + # - test-python + # - test-python # skip python tox run for now, as we don't yet have multiple test environments to support. #- test-rest-python From 85061125ea08822f3d82807516e022175561ecb9 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 13:36:28 -0700 Subject: [PATCH 50/53] remove ramda --- packages/contract-wrappers/package.json | 2 -- .../src/contract_wrappers/coordinator_wrapper.ts | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 67a6f1434b..7b30781da7 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -81,7 +81,6 @@ "@0x/typescript-typings": "^4.2.2", "@0x/utils": "^4.3.1", "@0x/web3-wrapper": "^6.0.5", - "@types/ramda": "^0.26.8", "ethereum-types": "^2.1.2", "ethereumjs-abi": "0.6.5", "ethereumjs-blockstream": "6.0.0", @@ -90,7 +89,6 @@ "http-status-codes": "^1.3.2", "js-sha3": "^0.7.0", "lodash": "^4.17.11", - "ramda": "^0.26.1", "uuid": "^3.3.2" }, "publishConfig": { diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts index 952764259d..44b88a99e1 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts @@ -8,7 +8,7 @@ import { BigNumber, fetchAsync } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { ContractAbi } from 'ethereum-types'; import * as HttpStatus from 'http-status-codes'; -import { flatten } from 'ramda'; +import { flatten } from 'lodash'; import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; import { txOptsSchema } from '../schemas/tx_opts_schema'; @@ -651,8 +651,8 @@ export class CoordinatorWrapper extends ContractWrapper { formatRawResponse(resp.body as CoordinatorServerApprovalRawResponse), ); - const allSignatures = flatten(allApprovals.map(a => a.signatures)); - const allExpirationTimes = flatten(allApprovals.map(a => a.expirationTimeSeconds)); + const allSignatures = flatten(allApprovals.map(a => a.signatures)); + const allExpirationTimes = flatten(allApprovals.map(a => a.expirationTimeSeconds)); // submit transaction with approvals const txHash = await this._submitCoordinatorTransactionAsync( @@ -673,7 +673,7 @@ export class CoordinatorWrapper extends ContractWrapper { const orders = serverEndpointsToOrders[endpoint]; return orders; }); - const approvedOrders = flatten(approvedOrdersNested.concat(notCoordinatorOrders)); + const approvedOrders = flatten(approvedOrdersNested.concat(notCoordinatorOrders)); // lookup orders with errors const errorsWithOrders = errorResponses.map(resp => { From 0cc6e989497807d5dacc4c5b276136e4ecf54add Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 14:01:04 -0700 Subject: [PATCH 51/53] restore circle config and changelog --- .circleci/config.yml | 66 +++++++++++------------ packages/contract-wrappers/CHANGELOG.json | 9 ++++ 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 076a4ab7ec..c5bef5e04a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -393,39 +393,39 @@ workflows: main: jobs: - build - # - build-website: - # requires: - # - build - # - test-contracts-ganache: - # requires: - # - build - # TODO(albrow): Tests always fail on Geth right now because our fork - # is outdated. Uncomment once we have updated our Geth fork. - # - test-contracts-geth: - # requires: - # - build - # - test-pipeline: - # requires: - # - build - # - test-rest: - # requires: - # - build - # - static-tests: - # requires: - # - build + - build-website: + requires: + - build + - test-contracts-ganache: + requires: + - build + TODO(albrow): Tests always fail on Geth right now because our fork + is outdated. Uncomment once we have updated our Geth fork. + - test-contracts-geth: + requires: + - build + - test-pipeline: + requires: + - build + - test-rest: + requires: + - build + - static-tests: + requires: + - build - test-publish: requires: - build - # - test-doc-generation: - # requires: - # - build - # - submit-coverage: - # requires: - # - test-rest - # - test-python - # - static-tests-python: - # requires: - # - test-python - # - test-python - # skip python tox run for now, as we don't yet have multiple test environments to support. - #- test-rest-python + - test-doc-generation: + requires: + - build + - submit-coverage: + requires: + - test-rest + - test-python + - static-tests-python: + requires: + - test-python + - test-python + skip python tox run for now, as we don't yet have multiple test environments to support. + - test-rest-python diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index d50ece68f3..a7f4195cd9 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "9.1.0", + "changes": [ + { + "note": "Added CoordinatorWrapper to support orders with the Coordinator extension contract", + "pr": 1792 + } + ] + }, { "version": "9.0.0", "changes": [ From 797d0362952f7e9f634e7bace25f90f374114a64 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 14:03:40 -0700 Subject: [PATCH 52/53] fix circle config --- .circleci/config.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c5bef5e04a..ea23a41849 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -399,11 +399,11 @@ workflows: - test-contracts-ganache: requires: - build - TODO(albrow): Tests always fail on Geth right now because our fork - is outdated. Uncomment once we have updated our Geth fork. - - test-contracts-geth: - requires: - - build + # TODO(albrow): Tests always fail on Geth right now because our fork + # is outdated. Uncomment once we have updated our Geth fork. + # - test-contracts-geth: + # requires: + # - build - test-pipeline: requires: - build @@ -427,5 +427,5 @@ workflows: requires: - test-python - test-python - skip python tox run for now, as we don't yet have multiple test environments to support. - - test-rest-python + # skip python tox run for now, as we don't yet have multiple test environments to support. + #- test-rest-python From fe3b56d1a5d2f3c44239ab6cf8f0914a0cb593f2 Mon Sep 17 00:00:00 2001 From: xianny Date: Thu, 9 May 2019 15:25:32 -0700 Subject: [PATCH 53/53] bump circleci