From fba3870ef19f54a00dbde8dd6eaf777b4a01e422 Mon Sep 17 00:00:00 2001 From: fabioberger Date: Thu, 7 Nov 2019 12:46:34 +0000 Subject: [PATCH] Move ExchangeTransferSimulator into contract-exchange tests since that's the only place it's still used and we no longer want to expose it to external developers --- contracts/exchange/package.json | 2 +- .../test/exchange_transfer_simulator_test.ts | 68 +- ...act_balance_and_proxy_allowance_fetcher.ts | 0 ..._balance_and_proxy_allowance_lazy_store.ts | 0 ...abstract_order_filled_cancelled_fetcher.ts | 7 - ...tract_order_filled_cancelled_lazy_store.ts | 2 - ...set_balance_and_proxy_allowance_fetcher.ts | 2 +- .../utils}/exchange_transfer_simulator.ts | 18 +- .../utils/fill_order_combinatorial_utils.ts | 5 +- .../test/utils/fill_order_simulator.ts | 12 +- ...set_balance_and_proxy_allowance_fetcher.ts | 2 +- ...c20_balance_and_proxy_allowance_fetcher.ts | 4 +- .../balance_and_proxy_allowance_lazy_store.ts | 0 .../order_filled_cancelled_lazy_store.ts | 16 - .../src/generated-wrappers/zrx_token.ts | 1268 ----------------- packages/order-utils/src/index.ts | 11 - packages/order-utils/src/order_state_utils.ts | 363 ----- .../order-utils/src/order_validation_utils.ts | 204 --- .../test/order_state_utils_test.ts | 142 -- .../test/order_validation_utils_test.ts | 70 - 20 files changed, 56 insertions(+), 2140 deletions(-) rename {packages/order-utils => contracts/exchange}/test/exchange_transfer_simulator_test.ts (78%) rename {packages/order-utils/src => contracts/exchange/test/utils}/abstract/abstract_balance_and_proxy_allowance_fetcher.ts (100%) rename {packages/order-utils/src => contracts/exchange/test/utils}/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts (100%) rename {packages/order-utils/src => contracts/exchange/test/utils}/abstract/abstract_order_filled_cancelled_fetcher.ts (66%) rename {packages/order-utils/src => contracts/exchange/test/utils}/abstract/abstract_order_filled_cancelled_lazy_store.ts (80%) rename {packages/order-utils/src => contracts/exchange/test/utils}/asset_balance_and_proxy_allowance_fetcher.ts (94%) rename {packages/order-utils/src => contracts/exchange/test/utils}/exchange_transfer_simulator.ts (91%) rename {packages/order-utils => contracts/exchange}/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts (86%) rename {packages/order-utils/src => contracts/exchange/test/utils}/store/balance_and_proxy_allowance_lazy_store.ts (100%) rename {packages/order-utils/src => contracts/exchange/test/utils}/store/order_filled_cancelled_lazy_store.ts (81%) delete mode 100644 packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts delete mode 100644 packages/order-utils/src/order_state_utils.ts delete mode 100644 packages/order-utils/src/order_validation_utils.ts delete mode 100644 packages/order-utils/test/order_state_utils_test.ts delete mode 100644 packages/order-utils/test/order_validation_utils_test.ts diff --git a/contracts/exchange/package.json b/contracts/exchange/package.json index 26787aec5e..12d94b240b 100644 --- a/contracts/exchange/package.json +++ b/contracts/exchange/package.json @@ -76,7 +76,7 @@ "dependencies": { "@0x/base-contract": "^5.5.0-beta.1", "@0x/contracts-asset-proxy": "^2.3.0-beta.1", - "@0x/contracts-dev-utils": "^0.1.0-beta.1", + "@0x/contracts-dev-utils": "^2.4.0-beta.1", "@0x/contracts-erc1155": "^1.2.0-beta.1", "@0x/contracts-erc20": "^2.3.0-beta.1", "@0x/contracts-erc721": "^2.2.0-beta.1", diff --git a/packages/order-utils/test/exchange_transfer_simulator_test.ts b/contracts/exchange/test/exchange_transfer_simulator_test.ts similarity index 78% rename from packages/order-utils/test/exchange_transfer_simulator_test.ts rename to contracts/exchange/test/exchange_transfer_simulator_test.ts index 1d64401482..bb7ba0faaf 100644 --- a/packages/order-utils/test/exchange_transfer_simulator_test.ts +++ b/contracts/exchange/test/exchange_transfer_simulator_test.ts @@ -1,29 +1,21 @@ -import { - DevUtilsContract, - DummyERC20TokenContract, - ERC20ProxyContract, - ERC20TokenContract, -} from '@0x/abi-gen-wrappers'; -import * as artifacts from '@0x/contract-artifacts'; -import { BlockchainLifecycle, devConstants } from '@0x/dev-utils'; +import { artifacts as assetProxyArtifacts, ERC20ProxyContract } from '@0x/contracts-asset-proxy'; +import { DevUtilsContract } from '@0x/contracts-dev-utils'; +import { artifacts as erc20Artifacts, DummyERC20TokenContract, ERC20TokenContract } from '@0x/contracts-erc20'; +import { blockchainTests, chaiSetup, constants } from '@0x/contracts-test-utils'; +import { TradeSide, TransferType } from '@0x/order-utils'; import { ExchangeContractErrs } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import { constants } from '../src/constants'; -import { ExchangeTransferSimulator } from '../src/exchange_transfer_simulator'; -import { BalanceAndProxyAllowanceLazyStore } from '../src/store/balance_and_proxy_allowance_lazy_store'; -import { TradeSide, TransferType } from '../src/types'; - -import { chaiSetup } from './utils/chai_setup'; +import { ExchangeTransferSimulator } from './utils/exchange_transfer_simulator'; import { SimpleERC20BalanceAndProxyAllowanceFetcher } from './utils/simple_erc20_balance_and_proxy_allowance_fetcher'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; +import { BalanceAndProxyAllowanceLazyStore } from './utils/store/balance_and_proxy_allowance_lazy_store'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -describe('ExchangeTransferSimulator', async () => { +const GAS_LIMIT = 9e6; + +blockchainTests('ExchangeTransferSimulator', env => { const transferAmount = new BigNumber(5); let userAddresses: string[]; let dummyERC20Token: DummyERC20TokenContract; @@ -34,25 +26,25 @@ describe('ExchangeTransferSimulator', async () => { let exchangeTransferSimulator: ExchangeTransferSimulator; let txHash: string; let erc20ProxyAddress: string; - const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); + const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, env.provider); before(async function(): Promise { const mochaTestTimeoutMs = 20000; this.timeout(mochaTestTimeoutMs); // tslint:disable-line:no-invalid-this - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + userAddresses = await env.web3Wrapper.getAvailableAddressesAsync(); [coinbase, sender, recipient] = userAddresses; const txDefaults = { - gas: devConstants.GAS_LIMIT, - from: devConstants.TESTRPC_FIRST_ADDRESS, + gas: GAS_LIMIT, + from: userAddresses[0], }; - await blockchainLifecycle.startAsync(); + await env.blockchainLifecycle.startAsync(); const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync( - artifacts.ERC20Proxy, - provider, + assetProxyArtifacts.ERC20Proxy, + env.provider, txDefaults, - artifacts, + assetProxyArtifacts, ); erc20ProxyAddress = erc20Proxy.address; @@ -62,10 +54,10 @@ describe('ExchangeTransferSimulator', async () => { const decimals = new BigNumber(18); // tslint:disable-next-line:no-unused-variable dummyERC20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - artifacts.DummyERC20Token, - provider, + erc20Artifacts.DummyERC20Token, + env.provider, txDefaults, - artifacts, + erc20Artifacts, name, symbol, decimals, @@ -75,13 +67,13 @@ describe('ExchangeTransferSimulator', async () => { exampleAssetData = await devUtils.encodeERC20AssetData.callAsync(dummyERC20Token.address); }); beforeEach(async () => { - await blockchainLifecycle.startAsync(); + await env.blockchainLifecycle.startAsync(); }); afterEach(async () => { - await blockchainLifecycle.revertAsync(); + await env.blockchainLifecycle.revertAsync(); }); after(async () => { - await blockchainLifecycle.revertAsync(); + await env.blockchainLifecycle.revertAsync(); }); describe('#transferFromAsync', function(): void { // HACK: For some reason these tests need a slightly longer timeout @@ -95,7 +87,7 @@ describe('ExchangeTransferSimulator', async () => { const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore( simpleERC20BalanceAndProxyAllowanceFetcher, ); - exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore); + exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore, env.provider); }); it("throws if the user doesn't have enough allowance", async () => { return expect( @@ -113,7 +105,7 @@ describe('ExchangeTransferSimulator', async () => { txHash = await dummyERC20Token.approve.sendTransactionAsync(erc20ProxyAddress, transferAmount, { from: sender, }); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await env.web3Wrapper.awaitTransactionSuccessAsync(txHash); return expect( exchangeTransferSimulator.transferFromAsync( exampleAssetData, @@ -129,12 +121,12 @@ describe('ExchangeTransferSimulator', async () => { txHash = await dummyERC20Token.transfer.sendTransactionAsync(sender, transferAmount, { from: coinbase, }); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await env.web3Wrapper.awaitTransactionSuccessAsync(txHash); txHash = await dummyERC20Token.approve.sendTransactionAsync(erc20ProxyAddress, transferAmount, { from: sender, }); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await env.web3Wrapper.awaitTransactionSuccessAsync(txHash); await exchangeTransferSimulator.transferFromAsync( exampleAssetData, @@ -156,7 +148,7 @@ describe('ExchangeTransferSimulator', async () => { txHash = await dummyERC20Token.transfer.sendTransactionAsync(sender, transferAmount, { from: coinbase, }); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await env.web3Wrapper.awaitTransactionSuccessAsync(txHash); txHash = await dummyERC20Token.approve.sendTransactionAsync( erc20ProxyAddress, constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, @@ -164,7 +156,7 @@ describe('ExchangeTransferSimulator', async () => { from: sender, }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash); + await env.web3Wrapper.awaitTransactionSuccessAsync(txHash); await exchangeTransferSimulator.transferFromAsync( exampleAssetData, sender, diff --git a/packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_fetcher.ts similarity index 100% rename from packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_fetcher.ts rename to contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_fetcher.ts diff --git a/packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts b/contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts similarity index 100% rename from packages/order-utils/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts rename to contracts/exchange/test/utils/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts diff --git a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts b/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_fetcher.ts similarity index 66% rename from packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts rename to contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_fetcher.ts index 67df672b46..8a73e54fee 100644 --- a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_fetcher.ts +++ b/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_fetcher.ts @@ -1,4 +1,3 @@ -import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; /** @@ -13,10 +12,4 @@ export abstract class AbstractOrderFilledCancelledFetcher { * @return FilledTakerAmount */ public abstract async getFilledTakerAmountAsync(orderHash: string): Promise; - /** - * Whether an order is cancelled - * @param orderHash OrderHash of order we are interested in - * @return Whether or not the order is cancelled - */ - public abstract async isOrderCancelledAsync(signedOrder: SignedOrder): Promise; } diff --git a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts b/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_lazy_store.ts similarity index 80% rename from packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts rename to contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_lazy_store.ts index 2fe093d208..06b7799ff3 100644 --- a/packages/order-utils/src/abstract/abstract_order_filled_cancelled_lazy_store.ts +++ b/contracts/exchange/test/utils/abstract/abstract_order_filled_cancelled_lazy_store.ts @@ -1,9 +1,7 @@ -import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; export abstract class AbstractOrderFilledCancelledLazyStore { public abstract async getFilledTakerAmountAsync(orderHash: string): Promise; - public abstract async getIsCancelledAsync(signedOrder: SignedOrder): Promise; public abstract setFilledTakerAmount(orderHash: string, balance: BigNumber): void; public abstract deleteFilledTakerAmount(orderHash: string): void; public abstract setIsCancelled(orderHash: string, isCancelled: boolean): void; diff --git a/packages/order-utils/src/asset_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/asset_balance_and_proxy_allowance_fetcher.ts similarity index 94% rename from packages/order-utils/src/asset_balance_and_proxy_allowance_fetcher.ts rename to contracts/exchange/test/utils/asset_balance_and_proxy_allowance_fetcher.ts index 1cef5d3c73..84419dac4f 100644 --- a/packages/order-utils/src/asset_balance_and_proxy_allowance_fetcher.ts +++ b/contracts/exchange/test/utils/asset_balance_and_proxy_allowance_fetcher.ts @@ -1,4 +1,4 @@ -import { DevUtilsContract } from '@0x/abi-gen-wrappers'; +import { DevUtilsContract } from '@0x/contracts-dev-utils'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; diff --git a/packages/order-utils/src/exchange_transfer_simulator.ts b/contracts/exchange/test/utils/exchange_transfer_simulator.ts similarity index 91% rename from packages/order-utils/src/exchange_transfer_simulator.ts rename to contracts/exchange/test/utils/exchange_transfer_simulator.ts index c2338b617f..0403eb426d 100644 --- a/packages/order-utils/src/exchange_transfer_simulator.ts +++ b/contracts/exchange/test/utils/exchange_transfer_simulator.ts @@ -1,10 +1,10 @@ +import { DevUtilsContract } from '@0x/contracts-dev-utils'; +import { constants } from '@0x/contracts-test-utils'; +import { SupportedProvider, TradeSide, TransferType } from '@0x/order-utils'; import { AssetProxyId, ExchangeContractErrs } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store'; -import { assetDataUtils } from './asset_data_utils'; -import { constants } from './constants'; -import { TradeSide, TransferType } from './types'; enum FailureReason { Balance = 'balance', @@ -40,6 +40,7 @@ const ERR_MSG_MAPPING = { */ export class ExchangeTransferSimulator { private readonly _store: AbstractBalanceAndProxyAllowanceLazyStore; + private readonly _devUtils: DevUtilsContract; private static _throwValidationError( failureReason: FailureReason, tradeSide: TradeSide, @@ -53,8 +54,9 @@ export class ExchangeTransferSimulator { * @param store A class that implements AbstractBalanceAndProxyAllowanceLazyStore * @return an instance of ExchangeTransferSimulator */ - constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) { + constructor(store: AbstractBalanceAndProxyAllowanceLazyStore, provider: SupportedProvider) { this._store = store; + this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider); } /** * Simulates transferFrom call performed by a proxy @@ -75,7 +77,7 @@ export class ExchangeTransferSimulator { tradeSide: TradeSide, transferType: TransferType, ): Promise { - const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); + const assetProxyId = await this._devUtils.decodeAssetProxyId.callAsync(assetData); switch (assetProxyId) { case AssetProxyId.ERC1155: case AssetProxyId.ERC20: @@ -108,11 +110,11 @@ export class ExchangeTransferSimulator { break; } case AssetProxyId.MultiAsset: { - const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData); + const decodedAssetData = await this._devUtils.decodeMultiAssetData.callAsync(assetData); await this._decreaseBalanceAsync(assetData, from, amountInBaseUnits); await this._increaseBalanceAsync(assetData, to, amountInBaseUnits); - for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) { - const amountsElement = decodedAssetData.amounts[index]; + for (const [index, nestedAssetDataElement] of decodedAssetData[2].entries()) { + const amountsElement = decodedAssetData[1][index]; const totalAmount = amountInBaseUnits.times(amountsElement); await this.transferFromAsync( nestedAssetDataElement, diff --git a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts b/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts index 006088efea..f0dbcb3d2e 100644 --- a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts +++ b/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts @@ -7,7 +7,7 @@ import { } from '@0x/contracts-asset-proxy'; import { DevUtilsContract } from '@0x/contracts-dev-utils'; import { constants, expect, LogDecoder, orderUtils, signingUtils } from '@0x/contracts-test-utils'; -import { BalanceAndProxyAllowanceLazyStore, ExchangeRevertErrors, orderHashUtils } from '@0x/order-utils'; +import { ExchangeRevertErrors, orderHashUtils } from '@0x/order-utils'; import { FillResults, Order, SignatureType, SignedOrder } from '@0x/types'; import { BigNumber, errorUtils, providerUtils, RevertError, StringRevertError } from '@0x/utils'; import { SupportedProvider, Web3Wrapper } from '@0x/web3-wrapper'; @@ -35,6 +35,7 @@ import { import { FillOrderError, FillOrderSimulator } from './fill_order_simulator'; import { OrderFactoryFromScenario } from './order_factory_from_scenario'; import { SimpleAssetBalanceAndProxyAllowanceFetcher } from './simple_asset_balance_and_proxy_allowance_fetcher'; +import { BalanceAndProxyAllowanceLazyStore } from './store/balance_and_proxy_allowance_lazy_store'; const EMPTY_FILL_RESULTS = { takerAssetFilledAmount: constants.ZERO_AMOUNT, @@ -503,7 +504,7 @@ export class FillOrderCombinatorialUtils { takerAssetFillAmount: BigNumber, lazyStore: BalanceAndProxyAllowanceLazyStore, ): Promise { - const simulator = new FillOrderSimulator(lazyStore); + const simulator = new FillOrderSimulator(lazyStore, this.provider); return simulator.simulateFillOrderAsync(signedOrder, this.takerAddress, takerAssetFillAmount); } diff --git a/contracts/exchange/test/utils/fill_order_simulator.ts b/contracts/exchange/test/utils/fill_order_simulator.ts index 024bcc05b6..c3882fac6f 100644 --- a/contracts/exchange/test/utils/fill_order_simulator.ts +++ b/contracts/exchange/test/utils/fill_order_simulator.ts @@ -1,8 +1,7 @@ import { constants, orderUtils } from '@0x/contracts-test-utils'; import { - AbstractBalanceAndProxyAllowanceLazyStore as LazyStore, - ExchangeTransferSimulator, Order, + SupportedProvider, TradeSide, TransferType, } from '@0x/order-utils'; @@ -10,6 +9,11 @@ import { FillResults } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; +import { + AbstractBalanceAndProxyAllowanceLazyStore as LazyStore, +} from './abstract/abstract_balance_and_proxy_allowance_lazy_store'; +import { ExchangeTransferSimulator } from './exchange_transfer_simulator'; + export enum FillOrderError { OrderUnfillable = 'ORDER_UNFILLABLE', InvalidSender = 'INVALID_SENDER', @@ -27,9 +31,9 @@ export class FillOrderSimulator { public readonly lazyStore: LazyStore; private readonly _transferSimulator: ExchangeTransferSimulator; - constructor(lazyStore: LazyStore) { + constructor(lazyStore: LazyStore, provider: SupportedProvider) { this.lazyStore = lazyStore; - this._transferSimulator = new ExchangeTransferSimulator(lazyStore); + this._transferSimulator = new ExchangeTransferSimulator(lazyStore, provider); } public async simulateFillOrderAsync( diff --git a/contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts index 64b7dedbe2..998b6aa9dd 100644 --- a/contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts +++ b/contracts/exchange/test/utils/simple_asset_balance_and_proxy_allowance_fetcher.ts @@ -1,6 +1,6 @@ -import { AbstractBalanceAndProxyAllowanceFetcher } from '@0x/order-utils'; import { BigNumber } from '@0x/utils'; +import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; import { AssetWrapper } from './asset_wrapper'; export class SimpleAssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { diff --git a/packages/order-utils/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts b/contracts/exchange/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts similarity index 86% rename from packages/order-utils/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts rename to contracts/exchange/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts index d3ea8b4567..c85d117919 100644 --- a/packages/order-utils/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts +++ b/contracts/exchange/test/utils/simple_erc20_balance_and_proxy_allowance_fetcher.ts @@ -1,7 +1,7 @@ -import { ERC20TokenContract } from '@0x/abi-gen-wrappers'; +import { ERC20TokenContract } from '@0x/contracts-erc20'; import { BigNumber } from '@0x/utils'; -import { AbstractBalanceAndProxyAllowanceFetcher } from '../../src/abstract/abstract_balance_and_proxy_allowance_fetcher'; +import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; export class SimpleERC20BalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { private readonly _erc20TokenContract: ERC20TokenContract; diff --git a/packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts b/contracts/exchange/test/utils/store/balance_and_proxy_allowance_lazy_store.ts similarity index 100% rename from packages/order-utils/src/store/balance_and_proxy_allowance_lazy_store.ts rename to contracts/exchange/test/utils/store/balance_and_proxy_allowance_lazy_store.ts diff --git a/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts b/contracts/exchange/test/utils/store/order_filled_cancelled_lazy_store.ts similarity index 81% rename from packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts rename to contracts/exchange/test/utils/store/order_filled_cancelled_lazy_store.ts index 102574c431..7564011668 100644 --- a/packages/order-utils/src/store/order_filled_cancelled_lazy_store.ts +++ b/contracts/exchange/test/utils/store/order_filled_cancelled_lazy_store.ts @@ -1,10 +1,8 @@ -import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import { AbstractOrderFilledCancelledFetcher } from '../abstract/abstract_order_filled_cancelled_fetcher'; import { AbstractOrderFilledCancelledLazyStore } from '../abstract/abstract_order_filled_cancelled_lazy_store'; -import { orderHashUtils } from '../order_hash'; /** * Copy on read store for balances/proxyAllowances of tokens/accounts @@ -55,20 +53,6 @@ export class OrderFilledCancelledLazyStore implements AbstractOrderFilledCancell public deleteFilledTakerAmount(orderHash: string): void { delete this._filledTakerAmount[orderHash]; } - /** - * Check if an order has been cancelled - * @param orderHash OrderHash from order of interest - * @return Whether the order has been cancelled - */ - public async getIsCancelledAsync(signedOrder: SignedOrder): Promise { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - if (this._isCancelled[orderHash] === undefined) { - const isCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder); - this.setIsCancelled(orderHash, isCancelled); - } - const cachedIsCancelled = this._isCancelled[orderHash]; // tslint:disable-line:boolean-naming - return cachedIsCancelled; - } /** * Set whether an order has been cancelled or not * @param orderHash OrderHash from order of interest diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts b/packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts deleted file mode 100644 index 811787ec7b..0000000000 --- a/packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts +++ /dev/null @@ -1,1268 +0,0 @@ -// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming -// tslint:disable:whitespace no-unbound-method no-trailing-whitespace -// tslint:disable:no-unused-variable -import { BaseContract, SubscriptionManager, PromiseWithTransactionHash } from '@0x/base-contract'; -import { schemas } from '@0x/json-schemas'; -import { - BlockParam, - BlockParamLiteral, - BlockRange, - CallData, - ContractAbi, - ContractArtifact, - DecodedLogArgs, - LogWithDecodedArgs, - MethodAbi, - TransactionReceiptWithDecodedLogs, - TxData, - TxDataPayable, - SupportedProvider, -} from 'ethereum-types'; -import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils'; -import { - AwaitTransactionSuccessOpts, - EventCallback, - IndexedFilterValues, - SendTransactionOpts, - SimpleContractArtifact, -} from '@0x/types'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { assert } from '@0x/assert'; -import * as ethers from 'ethers'; -// tslint:enable:no-unused-variable - -export type ZRXTokenEventArgs = ZRXTokenTransferEventArgs | ZRXTokenApprovalEventArgs; - -export enum ZRXTokenEvents { - Transfer = 'Transfer', - Approval = 'Approval', -} - -export interface ZRXTokenTransferEventArgs extends DecodedLogArgs { - _from: string; - _to: string; - _value: BigNumber; -} - -export interface ZRXTokenApprovalEventArgs extends DecodedLogArgs { - _owner: string; - _spender: string; - _value: BigNumber; -} - -/* istanbul ignore next */ -// tslint:disable:no-parameter-reassignment -// tslint:disable-next-line:class-name -export class ZRXTokenContract extends BaseContract { - /** - * @ignore - */ - public static deployedBytecode: string | undefined; - public name = { - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('name()', []); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('name()'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - }; - public approve = { - /** - * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write - * Ethereum operation and will cost gas. - * @param txData Additional data for transaction - * @returns The hash of the transaction - */ - async sendTransactionAsync( - _spender: string, - _value: BigNumber, - txData?: Partial | undefined, - opts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isString('_spender', _spender); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('approve(address,uint256)', [ - _spender.toLowerCase(), - _value, - ]); - const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...txData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - if (txDataWithDefaults.from !== undefined) { - txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); - } - - if (opts.shouldValidate !== false) { - await self.approve.callAsync(_spender, _value, txDataWithDefaults); - } - - const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); - return txHash; - }, - /** - * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. - * If the transaction was mined, but reverted, an error is thrown. - * @param txData Additional data for transaction - * @param pollingIntervalMs Interval at which to poll for success - * @returns A promise that resolves when the transaction is successful - */ - awaitTransactionSuccessAsync( - _spender: string, - _value: BigNumber, - txData?: Partial, - opts: AwaitTransactionSuccessOpts = { shouldValidate: true }, - ): PromiseWithTransactionHash { - assert.isString('_spender', _spender); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const txHashPromise = self.approve.sendTransactionAsync(_spender.toLowerCase(), _value, txData, opts); - return new PromiseWithTransactionHash( - txHashPromise, - (async (): Promise => { - // When the transaction hash resolves, wait for it to be mined. - return self._web3Wrapper.awaitTransactionSuccessAsync( - await txHashPromise, - opts.pollingIntervalMs, - opts.timeoutMs, - ); - })(), - ); - }, - /** - * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. - * @param txData Additional data for transaction - * @returns The hash of the transaction - */ - async estimateGasAsync( - _spender: string, - _value: BigNumber, - txData?: Partial | undefined, - ): Promise { - assert.isString('_spender', _spender); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('approve(address,uint256)', [ - _spender.toLowerCase(), - _value, - ]); - const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...txData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - if (txDataWithDefaults.from !== undefined) { - txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); - } - - const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); - return gas; - }, - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync( - _spender: string, - _value: BigNumber, - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise { - assert.isString('_spender', _spender); - assert.isBigNumber('_value', _value); - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('approve(address,uint256)', [ - _spender.toLowerCase(), - _value, - ]); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - /** - * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before - * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used - * to create a 0x transaction (see protocol spec for more details). - * @returns The ABI encoded transaction data as a string - */ - getABIEncodedTransactionData(_spender: string, _value: BigNumber): string { - assert.isString('_spender', _spender); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const abiEncodedTransactionData = self._strictEncodeArguments('approve(address,uint256)', [ - _spender.toLowerCase(), - _value, - ]); - return abiEncodedTransactionData; - }, - /** - * Returns the 4 byte function selector as a hex string. - */ - getSelector(): string { - const self = (this as any) as ZRXTokenContract; - const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); - return abiEncoder.getSelector(); - }, - }; - public totalSupply = { - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('totalSupply()', []); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('totalSupply()'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - }; - /** - * ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. - */ - public transferFrom = { - /** - * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write - * Ethereum operation and will cost gas. - * @param _from Address to transfer from. - * @param _to Address to transfer to. - * @param _value Amount to transfer. - * @param txData Additional data for transaction - * @returns The hash of the transaction - */ - async sendTransactionAsync( - _from: string, - _to: string, - _value: BigNumber, - txData?: Partial | undefined, - opts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isString('_from', _from); - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('transferFrom(address,address,uint256)', [ - _from.toLowerCase(), - _to.toLowerCase(), - _value, - ]); - const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...txData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - if (txDataWithDefaults.from !== undefined) { - txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); - } - - if (opts.shouldValidate !== false) { - await self.transferFrom.callAsync(_from, _to, _value, txDataWithDefaults); - } - - const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); - return txHash; - }, - /** - * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. - * If the transaction was mined, but reverted, an error is thrown. - * @param _from Address to transfer from. - * @param _to Address to transfer to. - * @param _value Amount to transfer. - * @param txData Additional data for transaction - * @param pollingIntervalMs Interval at which to poll for success - * @returns A promise that resolves when the transaction is successful - */ - awaitTransactionSuccessAsync( - _from: string, - _to: string, - _value: BigNumber, - txData?: Partial, - opts: AwaitTransactionSuccessOpts = { shouldValidate: true }, - ): PromiseWithTransactionHash { - assert.isString('_from', _from); - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const txHashPromise = self.transferFrom.sendTransactionAsync( - _from.toLowerCase(), - _to.toLowerCase(), - _value, - txData, - opts, - ); - return new PromiseWithTransactionHash( - txHashPromise, - (async (): Promise => { - // When the transaction hash resolves, wait for it to be mined. - return self._web3Wrapper.awaitTransactionSuccessAsync( - await txHashPromise, - opts.pollingIntervalMs, - opts.timeoutMs, - ); - })(), - ); - }, - /** - * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. - * @param _from Address to transfer from. - * @param _to Address to transfer to. - * @param _value Amount to transfer. - * @param txData Additional data for transaction - * @returns The hash of the transaction - */ - async estimateGasAsync( - _from: string, - _to: string, - _value: BigNumber, - txData?: Partial | undefined, - ): Promise { - assert.isString('_from', _from); - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('transferFrom(address,address,uint256)', [ - _from.toLowerCase(), - _to.toLowerCase(), - _value, - ]); - const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...txData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - if (txDataWithDefaults.from !== undefined) { - txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); - } - - const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); - return gas; - }, - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - * @param _from Address to transfer from. - * @param _to Address to transfer to. - * @param _value Amount to transfer. - * @returns Success of transfer. - */ - async callAsync( - _from: string, - _to: string, - _value: BigNumber, - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise { - assert.isString('_from', _from); - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('transferFrom(address,address,uint256)', [ - _from.toLowerCase(), - _to.toLowerCase(), - _value, - ]); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - /** - * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before - * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used - * to create a 0x transaction (see protocol spec for more details). - * @param _from Address to transfer from. - * @param _to Address to transfer to. - * @param _value Amount to transfer. - * @returns The ABI encoded transaction data as a string - */ - getABIEncodedTransactionData(_from: string, _to: string, _value: BigNumber): string { - assert.isString('_from', _from); - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const abiEncodedTransactionData = self._strictEncodeArguments('transferFrom(address,address,uint256)', [ - _from.toLowerCase(), - _to.toLowerCase(), - _value, - ]); - return abiEncodedTransactionData; - }, - /** - * Returns the 4 byte function selector as a hex string. - */ - getSelector(): string { - const self = (this as any) as ZRXTokenContract; - const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); - return abiEncoder.getSelector(); - }, - }; - public decimals = { - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('decimals()', []); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('decimals()'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - }; - public balanceOf = { - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync( - _owner: string, - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise { - assert.isString('_owner', _owner); - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('balanceOf(address)', [_owner.toLowerCase()]); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - }; - public symbol = { - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('symbol()', []); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('symbol()'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - }; - public transfer = { - /** - * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write - * Ethereum operation and will cost gas. - * @param txData Additional data for transaction - * @returns The hash of the transaction - */ - async sendTransactionAsync( - _to: string, - _value: BigNumber, - txData?: Partial | undefined, - opts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [_to.toLowerCase(), _value]); - const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...txData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - if (txDataWithDefaults.from !== undefined) { - txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); - } - - if (opts.shouldValidate !== false) { - await self.transfer.callAsync(_to, _value, txDataWithDefaults); - } - - const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); - return txHash; - }, - /** - * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. - * If the transaction was mined, but reverted, an error is thrown. - * @param txData Additional data for transaction - * @param pollingIntervalMs Interval at which to poll for success - * @returns A promise that resolves when the transaction is successful - */ - awaitTransactionSuccessAsync( - _to: string, - _value: BigNumber, - txData?: Partial, - opts: AwaitTransactionSuccessOpts = { shouldValidate: true }, - ): PromiseWithTransactionHash { - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const txHashPromise = self.transfer.sendTransactionAsync(_to.toLowerCase(), _value, txData, opts); - return new PromiseWithTransactionHash( - txHashPromise, - (async (): Promise => { - // When the transaction hash resolves, wait for it to be mined. - return self._web3Wrapper.awaitTransactionSuccessAsync( - await txHashPromise, - opts.pollingIntervalMs, - opts.timeoutMs, - ); - })(), - ); - }, - /** - * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. - * @param txData Additional data for transaction - * @returns The hash of the transaction - */ - async estimateGasAsync(_to: string, _value: BigNumber, txData?: Partial | undefined): Promise { - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [_to.toLowerCase(), _value]); - const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...txData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - if (txDataWithDefaults.from !== undefined) { - txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); - } - - const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); - return gas; - }, - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync( - _to: string, - _value: BigNumber, - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise { - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [_to.toLowerCase(), _value]); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - /** - * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before - * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used - * to create a 0x transaction (see protocol spec for more details). - * @returns The ABI encoded transaction data as a string - */ - getABIEncodedTransactionData(_to: string, _value: BigNumber): string { - assert.isString('_to', _to); - assert.isBigNumber('_value', _value); - const self = (this as any) as ZRXTokenContract; - const abiEncodedTransactionData = self._strictEncodeArguments('transfer(address,uint256)', [ - _to.toLowerCase(), - _value, - ]); - return abiEncodedTransactionData; - }, - /** - * Returns the 4 byte function selector as a hex string. - */ - getSelector(): string { - const self = (this as any) as ZRXTokenContract; - const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); - return abiEncoder.getSelector(); - }, - }; - public allowance = { - /** - * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an - * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas - * since they don't modify state. - */ - async callAsync( - _owner: string, - _spender: string, - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise { - assert.isString('_owner', _owner); - assert.isString('_spender', _spender); - assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (defaultBlock !== undefined) { - assert.isBlockParam('defaultBlock', defaultBlock); - } - const self = (this as any) as ZRXTokenContract; - const encodedData = self._strictEncodeArguments('allowance(address,address)', [ - _owner.toLowerCase(), - _spender.toLowerCase(), - ]); - const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { - to: self.address, - ...callData, - data: encodedData, - }, - self._web3Wrapper.getContractDefaults(), - ); - callDataWithDefaults.from = callDataWithDefaults.from - ? callDataWithDefaults.from.toLowerCase() - : callDataWithDefaults.from; - let rawCallResult; - try { - rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); - } catch (err) { - BaseContract._throwIfThrownErrorIsRevertError(err); - throw err; - } - BaseContract._throwIfCallResultIsRevertError(rawCallResult); - const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); - // tslint:disable boolean-naming - const result = abiEncoder.strictDecodeReturnValue(rawCallResult); - // tslint:enable boolean-naming - return result; - }, - }; - private readonly _subscriptionManager: SubscriptionManager; - public static async deployFrom0xArtifactAsync( - artifact: ContractArtifact | SimpleContractArtifact, - supportedProvider: SupportedProvider, - txDefaults: Partial, - logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, - ): Promise { - assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - if (artifact.compilerOutput === undefined) { - throw new Error('Compiler output not found in the artifact file'); - } - const provider = providerUtils.standardizeOrThrow(supportedProvider); - const bytecode = artifact.compilerOutput.evm.bytecode.object; - const abi = artifact.compilerOutput.abi; - const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; - if (Object.keys(logDecodeDependencies) !== undefined) { - for (const key of Object.keys(logDecodeDependencies)) { - logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; - } - } - return ZRXTokenContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); - } - public static async deployAsync( - bytecode: string, - abi: ContractAbi, - supportedProvider: SupportedProvider, - txDefaults: Partial, - logDecodeDependencies: { [contractName: string]: ContractAbi }, - ): Promise { - assert.isHexString('bytecode', bytecode); - assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ - schemas.addressSchema, - schemas.numberSchema, - schemas.jsNumber, - ]); - const provider = providerUtils.standardizeOrThrow(supportedProvider); - const constructorAbi = BaseContract._lookupConstructorAbi(abi); - [] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString); - const iface = new ethers.utils.Interface(abi); - const deployInfo = iface.deployFunction; - const txData = deployInfo.encode(bytecode, []); - const web3Wrapper = new Web3Wrapper(provider); - const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( - { data: txData }, - txDefaults, - web3Wrapper.estimateGasAsync.bind(web3Wrapper), - ); - const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); - logUtils.log(`transactionHash: ${txHash}`); - const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); - logUtils.log(`ZRXToken successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ZRXTokenContract( - txReceipt.contractAddress as string, - provider, - txDefaults, - logDecodeDependencies, - ); - contractInstance.constructorArgs = []; - return contractInstance; - } - - /** - * @returns The contract ABI - */ - public static ABI(): ContractAbi { - const abi = [ - { - constant: true, - inputs: [], - name: 'name', - outputs: [ - { - name: '', - type: 'string', - }, - ], - payable: false, - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_spender', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'approve', - outputs: [ - { - name: '', - type: 'bool', - }, - ], - payable: false, - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'totalSupply', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_from', - type: 'address', - }, - { - name: '_to', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'transferFrom', - outputs: [ - { - name: '', - type: 'bool', - }, - ], - payable: false, - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'decimals', - outputs: [ - { - name: '', - type: 'uint8', - }, - ], - payable: false, - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '_owner', - type: 'address', - }, - ], - name: 'balanceOf', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'symbol', - outputs: [ - { - name: '', - type: 'string', - }, - ], - payable: false, - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_to', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'transfer', - outputs: [ - { - name: '', - type: 'bool', - }, - ], - payable: false, - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '_owner', - type: 'address', - }, - { - name: '_spender', - type: 'address', - }, - ], - name: 'allowance', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - type: 'function', - }, - { - inputs: [], - outputs: [], - payable: false, - type: 'constructor', - }, - { - anonymous: false, - inputs: [ - { - name: '_from', - type: 'address', - indexed: true, - }, - { - name: '_to', - type: 'address', - indexed: true, - }, - { - name: '_value', - type: 'uint256', - indexed: false, - }, - ], - name: 'Transfer', - outputs: [], - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - name: '_owner', - type: 'address', - indexed: true, - }, - { - name: '_spender', - type: 'address', - indexed: true, - }, - { - name: '_value', - type: 'uint256', - indexed: false, - }, - ], - name: 'Approval', - outputs: [], - type: 'event', - }, - ] as ContractAbi; - return abi; - } - /** - * Subscribe to an event type emitted by the ZRXToken contract. - * @param eventName The ZRXToken contract event you would like to subscribe to. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` - * @param callback Callback that gets called when a log is added/removed - * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) - * @return Subscription token used later to unsubscribe - */ - public subscribe( - eventName: ZRXTokenEvents, - indexFilterValues: IndexedFilterValues, - callback: EventCallback, - isVerbose: boolean = false, - blockPollingIntervalMs?: number, - ): string { - assert.doesBelongToStringEnum('eventName', eventName, ZRXTokenEvents); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - assert.isFunction('callback', callback); - const subscriptionToken = this._subscriptionManager.subscribe( - this.address, - eventName, - indexFilterValues, - ZRXTokenContract.ABI(), - callback, - isVerbose, - blockPollingIntervalMs, - ); - return subscriptionToken; - } - /** - * Cancel a subscription - * @param subscriptionToken Subscription token returned by `subscribe()` - */ - public unsubscribe(subscriptionToken: string): void { - this._subscriptionManager.unsubscribe(subscriptionToken); - } - /** - * Cancels all existing subscriptions - */ - public unsubscribeAll(): void { - this._subscriptionManager.unsubscribeAll(); - } - /** - * Gets historical logs without creating a subscription - * @param eventName The ZRXToken contract event you would like to subscribe to. - * @param blockRange Block range to get logs from. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` - * @return Array of logs that match the parameters - */ - public async getLogsAsync( - eventName: ZRXTokenEvents, - blockRange: BlockRange, - indexFilterValues: IndexedFilterValues, - ): Promise>> { - assert.doesBelongToStringEnum('eventName', eventName, ZRXTokenEvents); - assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - const logs = await this._subscriptionManager.getLogsAsync( - this.address, - eventName, - blockRange, - indexFilterValues, - ZRXTokenContract.ABI(), - ); - return logs; - } - constructor( - address: string, - supportedProvider: SupportedProvider, - txDefaults?: Partial, - logDecodeDependencies?: { [contractName: string]: ContractAbi }, - deployedBytecode: string | undefined = ZRXTokenContract.deployedBytecode, - ) { - super( - 'ZRXToken', - ZRXTokenContract.ABI(), - address, - supportedProvider, - txDefaults, - logDecodeDependencies, - deployedBytecode, - ); - classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); - this._subscriptionManager = new SubscriptionManager( - ZRXTokenContract.ABI(), - this._web3Wrapper, - ); - } -} - -// tslint:disable:max-file-line-count -// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align -// tslint:enable:trailing-comma whitespace no-trailing-whitespace diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 3b20d0ea14..75bb536cf0 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -15,17 +15,6 @@ export { sortingUtils } from './sorting_utils'; export { orderParsingUtils } from './parsing_utils'; export { orderCalculationUtils } from './order_calculation_utils'; -export { OrderStateUtils } from './order_state_utils'; -export { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; -export { AbstractBalanceAndProxyAllowanceLazyStore } from './abstract/abstract_balance_and_proxy_allowance_lazy_store'; -export { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher'; -export { AbstractOrderFilledCancelledLazyStore } from './abstract/abstract_order_filled_cancelled_lazy_store'; - -export { OrderValidationUtils } from './order_validation_utils'; -export { ExchangeTransferSimulator } from './exchange_transfer_simulator'; -export { BalanceAndProxyAllowanceLazyStore } from './store/balance_and_proxy_allowance_lazy_store'; -export { OrderFilledCancelledLazyStore } from './store/order_filled_cancelled_lazy_store'; - export { eip712Utils } from './eip712_utils'; export { diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts deleted file mode 100644 index 72d6c48410..0000000000 --- a/packages/order-utils/src/order_state_utils.ts +++ /dev/null @@ -1,363 +0,0 @@ -import { - AssetProxyId, - ERC20AssetData, - ERC721AssetData, - ExchangeContractErrs, - MultiAssetData, - ObjectMap, - OrderRelevantState, - OrderState, - OrderStateInvalid, - OrderStateValid, - SignedOrder, - SingleAssetData, -} from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher'; -import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher'; -import { assetDataUtils } from './asset_data_utils'; -import { orderHashUtils } from './order_hash'; -import { OrderValidationUtils } from './order_validation_utils'; -import { RemainingFillableCalculator } from './remaining_fillable_calculator'; -import { utils } from './utils'; - -interface SidedOrderRelevantState { - isMakerSide: boolean; - traderBalance: BigNumber; - traderIndividualBalances: ObjectMap; - traderProxyAllowance: BigNumber; - traderIndividualProxyAllowances: ObjectMap; - traderFeeBalance: BigNumber; - traderFeeProxyAllowance: BigNumber; - filledTakerAssetAmount: BigNumber; - remainingFillableAssetAmount: BigNumber; - isOrderCancelled: boolean; -} -interface OrderValidResult { - isValid: true; -} -interface OrderInvalidResult { - isValid: false; - error: ExchangeContractErrs; -} -type OrderValidationResult = OrderValidResult | OrderInvalidResult; - -export class OrderStateUtils { - private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher; - private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher; - private static _validateIfOrderIsValid( - signedOrder: SignedOrder, - sidedOrderRelevantState: SidedOrderRelevantState, - ): OrderValidationResult { - const isMakerSide = sidedOrderRelevantState.isMakerSide; - if (sidedOrderRelevantState.isOrderCancelled) { - return { isValid: false, error: ExchangeContractErrs.OrderCancelled }; - } - const availableTakerAssetAmount = signedOrder.takerAssetAmount.minus( - sidedOrderRelevantState.filledTakerAssetAmount, - ); - if (availableTakerAssetAmount.eq(0)) { - return { isValid: false, error: ExchangeContractErrs.OrderRemainingFillAmountZero }; - } - - if (sidedOrderRelevantState.traderBalance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerBalance - : ExchangeContractErrs.InsufficientTakerBalance; - return { isValid: false, error }; - } - if (sidedOrderRelevantState.traderProxyAllowance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerAllowance - : ExchangeContractErrs.InsufficientTakerAllowance; - return { isValid: false, error }; - } - if (!signedOrder.makerFee.eq(0)) { - if (sidedOrderRelevantState.traderFeeBalance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerFeeBalance - : ExchangeContractErrs.InsufficientTakerFeeBalance; - return { isValid: false, error }; - } - if (sidedOrderRelevantState.traderFeeProxyAllowance.eq(0)) { - const error = isMakerSide - ? ExchangeContractErrs.InsufficientMakerFeeAllowance - : ExchangeContractErrs.InsufficientTakerFeeAllowance; - return { isValid: false, error }; - } - } - const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus( - sidedOrderRelevantState.filledTakerAssetAmount, - ); - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor( - remainingTakerAssetAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - if (isRoundingError) { - return { isValid: false, error: ExchangeContractErrs.OrderFillRoundingError }; - } - return { isValid: true }; - } - /** - * Instantiate OrderStateUtils - * @param balanceAndProxyAllowanceFetcher A class that is capable of fetching balances - * and proxyAllowances for Ethereum addresses. It must implement AbstractBalanceAndProxyAllowanceFetcher - * @param orderFilledCancelledFetcher A class that is capable of fetching whether an order - * is cancelled and how much of it has been filled. It must implement AbstractOrderFilledCancelledFetcher - * @return Instance of OrderStateUtils - */ - constructor( - balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher, - orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher, - ) { - this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher; - this._orderFilledCancelledFetcher = orderFilledCancelledFetcher; - } - /** - * Get the orderState for an "open" order (i.e where takerAddress=NULL_ADDRESS) - * This method will only check the maker's balance/allowance to calculate the - * OrderState. - * @param signedOrder The order of interest - * @return State relevant to the signedOrder, as well as whether the signedOrder is "valid". - * Validity is defined as a non-zero amount of the order can still be filled. - */ - public async getOpenOrderStateAsync(signedOrder: SignedOrder, transactionHash?: string): Promise { - const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder); - const sidedOrderRelevantState = { - isMakerSide: true, - traderBalance: orderRelevantState.makerBalance, - traderIndividualBalances: orderRelevantState.makerIndividualBalances, - traderProxyAllowance: orderRelevantState.makerProxyAllowance, - traderIndividualProxyAllowances: orderRelevantState.makerIndividualProxyAllowances, - traderFeeBalance: orderRelevantState.makerFeeBalance, - traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance, - filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount, - remainingFillableAssetAmount: orderRelevantState.remainingFillableMakerAssetAmount, - isOrderCancelled, - }; - const orderValidationResult = OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState); - if (orderValidationResult.isValid) { - const orderState: OrderStateValid = { - isValid: true, - orderHash, - orderRelevantState, - transactionHash, - }; - return orderState; - } else { - const orderState: OrderStateInvalid = { - isValid: false, - orderHash, - error: orderValidationResult.error, - transactionHash, - }; - return orderState; - } - } - /** - * Get state relevant to an order (i.e makerBalance, makerAllowance, filledTakerAssetAmount, etc... - * @param signedOrder Order of interest - * @return An instance of OrderRelevantState - */ - public async getOpenOrderRelevantStateAsync(signedOrder: SignedOrder): Promise { - const isMaker = true; - const sidedOrderRelevantState = await this._getSidedOrderRelevantStateAsync( - isMaker, - signedOrder, - signedOrder.takerAddress, - ); - const remainingFillableTakerAssetAmount = sidedOrderRelevantState.remainingFillableAssetAmount - .times(signedOrder.takerAssetAmount) - .dividedToIntegerBy(signedOrder.makerAssetAmount); - - const orderRelevantState = { - makerBalance: sidedOrderRelevantState.traderBalance, - makerIndividualBalances: sidedOrderRelevantState.traderIndividualBalances, - makerProxyAllowance: sidedOrderRelevantState.traderProxyAllowance, - makerIndividualProxyAllowances: sidedOrderRelevantState.traderIndividualProxyAllowances, - makerFeeBalance: sidedOrderRelevantState.traderFeeBalance, - makerFeeProxyAllowance: sidedOrderRelevantState.traderFeeProxyAllowance, - filledTakerAssetAmount: sidedOrderRelevantState.filledTakerAssetAmount, - remainingFillableMakerAssetAmount: sidedOrderRelevantState.remainingFillableAssetAmount, - remainingFillableTakerAssetAmount, - }; - return orderRelevantState; - } - /** - * Get the max amount of the supplied order's takerAmount that could still be filled - * @param signedOrder Order of interest - * @param takerAddress Hypothetical taker of the order - * @return fillableTakerAssetAmount - */ - public async getMaxFillableTakerAssetAmountAsync( - signedOrder: SignedOrder, - takerAddress: string, - ): Promise { - // Get max fillable amount for an order, considering the makers ability to fill - let isMaker = true; - const orderRelevantMakerState = await this._getSidedOrderRelevantStateAsync( - isMaker, - signedOrder, - signedOrder.takerAddress, - ); - const remainingFillableTakerAssetAmountGivenMakersStatus = signedOrder.makerAssetAmount.eq(0) - ? new BigNumber(0) - : utils.getPartialAmountFloor( - orderRelevantMakerState.remainingFillableAssetAmount, - signedOrder.makerAssetAmount, - signedOrder.takerAssetAmount, - ); - - // Get max fillable amount for an order, considering the takers ability to fill - isMaker = false; - const orderRelevantTakerState = await this._getSidedOrderRelevantStateAsync(isMaker, signedOrder, takerAddress); - const remainingFillableTakerAssetAmountGivenTakersStatus = orderRelevantTakerState.remainingFillableAssetAmount; - - // The min of these two in the actualy max fillable by either party - const fillableTakerAssetAmount = BigNumber.min( - remainingFillableTakerAssetAmountGivenMakersStatus, - remainingFillableTakerAssetAmountGivenTakersStatus, - ); - - return fillableTakerAssetAmount; - } - private async _getSidedOrderRelevantStateAsync( - isMakerSide: boolean, - signedOrder: SignedOrder, - takerAddress: string, - ): Promise { - let traderAddress; - let assetData; - let assetAmount; - let feeAssetData; - let feeAmount; - if (isMakerSide) { - traderAddress = signedOrder.makerAddress; - assetData = signedOrder.makerAssetData; - assetAmount = signedOrder.makerAssetAmount; - feeAssetData = signedOrder.makerFeeAssetData; - feeAmount = signedOrder.makerFee; - } else { - traderAddress = takerAddress; - assetData = signedOrder.takerAssetData; - assetAmount = signedOrder.takerAssetAmount; - feeAssetData = signedOrder.takerFeeAssetData; - feeAmount = signedOrder.takerFee; - } - const isPercentageFee = assetData === feeAssetData; - - const traderBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress); - const traderIndividualBalances = await this._getAssetBalancesAsync(assetData, traderAddress); - const traderProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - assetData, - traderAddress, - ); - const traderIndividualProxyAllowances = await this._getAssetProxyAllowancesAsync(assetData, traderAddress); - const traderFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync( - feeAssetData, - traderAddress, - ); - const traderFeeProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - feeAssetData, - traderAddress, - ); - - const transferrableTraderAssetAmount = BigNumber.min(traderProxyAllowance, traderBalance); - const transferrableFeeAssetAmount = BigNumber.min(traderFeeProxyAllowance, traderFeeBalance); - - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const filledTakerAssetAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash); - const totalMakerAssetAmount = signedOrder.makerAssetAmount; - const totalTakerAssetAmount = signedOrder.takerAssetAmount; - const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(signedOrder); - const remainingTakerAssetAmount = isOrderCancelled - ? new BigNumber(0) - : totalTakerAssetAmount.minus(filledTakerAssetAmount); - const remainingMakerAssetAmount = remainingTakerAssetAmount.eq(0) - ? new BigNumber(0) - : remainingTakerAssetAmount.times(totalMakerAssetAmount).dividedToIntegerBy(totalTakerAssetAmount); - const remainingAssetAmount = isMakerSide ? remainingMakerAssetAmount : remainingTakerAssetAmount; - - const remainingFillableCalculator = new RemainingFillableCalculator( - feeAmount, - assetAmount, - isPercentageFee, - transferrableTraderAssetAmount, - transferrableFeeAssetAmount, - remainingAssetAmount, - ); - const remainingFillableAssetAmount = remainingFillableCalculator.computeRemainingFillable(); - - const sidedOrderRelevantState = { - isMakerSide, - traderBalance, - traderIndividualBalances, - traderProxyAllowance, - traderIndividualProxyAllowances, - traderFeeBalance, - traderFeeProxyAllowance, - filledTakerAssetAmount, - remainingFillableAssetAmount, - isOrderCancelled, - }; - return sidedOrderRelevantState; - } - private async _getAssetBalancesAsync( - assetData: string, - traderAddress: string, - initialBalances: ObjectMap = {}, - ): Promise> { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - let balances: ObjectMap = { ...initialBalances }; - if (isERC20AssetData(decodedAssetData) || isERC721AssetData(decodedAssetData)) { - const balance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync(assetData, traderAddress); - // tslint:disable-next-line:no-unnecessary-type-assertion - const tokenAddress = (decodedAssetData as ERC20AssetData | ERC721AssetData).tokenAddress; - balances[tokenAddress] = - initialBalances[tokenAddress] === undefined ? balance : balances[tokenAddress].plus(balance); - } else if (isMultiAssetData(decodedAssetData)) { - for (const assetDataElement of (decodedAssetData as MultiAssetData).nestedAssetData) { - balances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, balances); - } - } - return balances; - } - private async _getAssetProxyAllowancesAsync( - assetData: string, - traderAddress: string, - initialAllowances: ObjectMap = {}, - ): Promise> { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - let allowances: ObjectMap = { ...initialAllowances }; - if (isERC20AssetData(decodedAssetData) || isERC721AssetData(decodedAssetData)) { - const allowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( - assetData, - traderAddress, - ); - // tslint:disable-next-line:no-unnecessary-type-assertion - const tokenAddress = (decodedAssetData as ERC20AssetData | ERC721AssetData).tokenAddress; - allowances[tokenAddress] = - initialAllowances[tokenAddress] === undefined ? allowance : allowances[tokenAddress].plus(allowance); - } else if (isMultiAssetData(decodedAssetData)) { - for (const assetDataElement of (decodedAssetData as MultiAssetData).nestedAssetData) { - allowances = await this._getAssetBalancesAsync(assetDataElement, traderAddress, allowances); - } - } - return allowances; - } -} - -function isERC20AssetData(decodedAssetData: SingleAssetData | MultiAssetData): boolean { - return decodedAssetData.assetProxyId === AssetProxyId.ERC20; -} -function isERC721AssetData(decodedAssetData: SingleAssetData | MultiAssetData): boolean { - return decodedAssetData.assetProxyId === AssetProxyId.ERC721; -} -function isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): boolean { - return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset; -} diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts deleted file mode 100644 index 19141c2208..0000000000 --- a/packages/order-utils/src/order_validation_utils.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { ExchangeContractErrs, RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber, providerUtils } from '@0x/utils'; -import { SupportedProvider, ZeroExProvider } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher'; -import { constants } from './constants'; -import { ExchangeTransferSimulator } from './exchange_transfer_simulator'; -import { orderHashUtils } from './order_hash'; -import { signatureUtils } from './signature_utils'; -import { TradeSide, TransferType, TypedDataError } from './types'; -import { utils } from './utils'; - -/** - * A utility class for validating orders - */ -export class OrderValidationUtils { - private readonly _orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher; - private readonly _provider: ZeroExProvider; - /** - * A TypeScript implementation mirroring the implementation of isRoundingError in the - * Exchange smart contract - * @param numerator Numerator value. When used to check an order, pass in `takerAssetFilledAmount` - * @param denominator Denominator value. When used to check an order, pass in `order.takerAssetAmount` - * @param target Target value. When used to check an order, pass in `order.makerAssetAmount` - */ - public static isRoundingErrorFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean { - // Solidity's mulmod() in JS - // Source: https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions - if (denominator.eq(0)) { - throw new Error('denominator cannot be 0'); - } - const remainder = target.multipliedBy(numerator).mod(denominator); - if (remainder.eq(0)) { - return false; // no rounding error - } - - // tslint:disable-next-line:custom-no-magic-numbers - const errPercentageTimes1000000 = remainder.multipliedBy(1000000).div(numerator.multipliedBy(target)); - // tslint:disable-next-line:custom-no-magic-numbers - const isError = errPercentageTimes1000000.gt(1000); - return isError; - } - - /** - * Validate that the maker & taker have sufficient balances/allowances - * to fill the supplied order to the fillTakerAssetAmount amount - * @param exchangeTradeEmulator ExchangeTradeEmulator to use - * @param signedOrder SignedOrder to test - * @param fillTakerAssetAmount Amount of takerAsset to fill the signedOrder - * @param senderAddress Sender of the fillOrder tx - */ - public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, - signedOrder: SignedOrder, - fillTakerAssetAmount: BigNumber, - senderAddress: string, - ): Promise { - const fillMakerTokenAmount = utils.getPartialAmountFloor( - fillTakerAssetAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - const makerFeeAmount = utils.getPartialAmountFloor( - fillTakerAssetAmount, - signedOrder.takerAssetAmount, - signedOrder.makerFee, - ); - const takerFeeAmount = utils.getPartialAmountFloor( - fillTakerAssetAmount, - signedOrder.takerAssetAmount, - signedOrder.takerFee, - ); - await exchangeTradeEmulator.transferFromAsync( - signedOrder.makerAssetData, - signedOrder.makerAddress, - senderAddress, - fillMakerTokenAmount, - TradeSide.Maker, - TransferType.Trade, - ); - await exchangeTradeEmulator.transferFromAsync( - signedOrder.takerAssetData, - senderAddress, - signedOrder.makerAddress, - fillTakerAssetAmount, - TradeSide.Taker, - TransferType.Trade, - ); - await exchangeTradeEmulator.transferFromAsync( - signedOrder.makerFeeAssetData, - signedOrder.makerAddress, - signedOrder.feeRecipientAddress, - makerFeeAmount, - TradeSide.Maker, - TransferType.Fee, - ); - await exchangeTradeEmulator.transferFromAsync( - signedOrder.takerFeeAssetData, - senderAddress, - signedOrder.feeRecipientAddress, - takerFeeAmount, - TradeSide.Taker, - TransferType.Fee, - ); - } - - private static _validateOrderNotExpiredOrThrow(expirationTimeSeconds: BigNumber): void { - const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); - if (expirationTimeSeconds.isLessThan(currentUnixTimestampSec)) { - throw new Error(RevertReason.OrderUnfillable); - } - } - /** - * Instantiate OrderValidationUtils - * @param orderFilledCancelledFetcher A module that implements the AbstractOrderFilledCancelledFetcher - * @param supportedProvider Web3 provider to use for JSON RPC calls - * @return An instance of OrderValidationUtils - */ - constructor( - orderFilledCancelledFetcher: AbstractOrderFilledCancelledFetcher, - supportedProvider: SupportedProvider, - ) { - this._orderFilledCancelledFetcher = orderFilledCancelledFetcher; - this._provider = providerUtils.standardizeOrThrow(supportedProvider); - } - - /** - * Validate a call to FillOrder and throw if it wouldn't succeed - * @param exchangeTradeEmulator ExchangeTradeEmulator to use - * @param signedOrder SignedOrder of interest - * @param fillTakerAssetAmount Amount we'd like to fill the order for - * @param takerAddress The taker of the order - */ - public async validateFillOrderThrowIfInvalidAsync( - exchangeTradeEmulator: ExchangeTransferSimulator, - signedOrder: SignedOrder, - fillTakerAssetAmount: BigNumber, - takerAddress: string, - ): Promise { - OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationTimeSeconds); - if (signedOrder.makerAssetAmount.eq(0) || signedOrder.takerAssetAmount.eq(0)) { - throw new Error(RevertReason.OrderUnfillable); - } - if (fillTakerAssetAmount.eq(0)) { - throw new Error(RevertReason.InvalidTakerAmount); - } - - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const isValid = await signatureUtils.isValidSignatureAsync( - this._provider, - orderHash, - signedOrder.signature, - signedOrder.makerAddress, - ); - if (!isValid) { - throw new Error(TypedDataError.InvalidSignature); - } - const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash); - if (signedOrder.takerAssetAmount.eq(filledTakerTokenAmount)) { - throw new Error(RevertReason.OrderUnfillable); - } - if (signedOrder.takerAddress !== constants.NULL_ADDRESS && signedOrder.takerAddress !== takerAddress) { - throw new Error(RevertReason.InvalidTaker); - } - const remainingTakerTokenAmount = signedOrder.takerAssetAmount.minus(filledTakerTokenAmount); - const desiredFillTakerTokenAmount = remainingTakerTokenAmount.isLessThan(fillTakerAssetAmount) - ? remainingTakerTokenAmount - : fillTakerAssetAmount; - try { - await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( - exchangeTradeEmulator, - signedOrder, - desiredFillTakerTokenAmount, - takerAddress, - ); - } catch (err) { - const transferFailedErrorMessages = [ - ExchangeContractErrs.InsufficientMakerBalance, - ExchangeContractErrs.InsufficientMakerFeeBalance, - ExchangeContractErrs.InsufficientTakerBalance, - ExchangeContractErrs.InsufficientTakerFeeBalance, - ExchangeContractErrs.InsufficientMakerAllowance, - ExchangeContractErrs.InsufficientMakerFeeAllowance, - ExchangeContractErrs.InsufficientTakerAllowance, - ExchangeContractErrs.InsufficientTakerFeeAllowance, - ]; - if (_.includes(transferFailedErrorMessages, err.message)) { - throw new Error(RevertReason.TransferFailed); - } - throw err; - } - - const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingErrorFloor( - desiredFillTakerTokenAmount, - signedOrder.takerAssetAmount, - signedOrder.makerAssetAmount, - ); - if (wouldRoundingErrorOccur) { - throw new Error(RevertReason.RoundingError); - } - return filledTakerTokenAmount; - } -} diff --git a/packages/order-utils/test/order_state_utils_test.ts b/packages/order-utils/test/order_state_utils_test.ts deleted file mode 100644 index ec0bfec57c..0000000000 --- a/packages/order-utils/test/order_state_utils_test.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { AbstractBalanceAndProxyAllowanceFetcher } from '../src/abstract/abstract_balance_and_proxy_allowance_fetcher'; -import { AbstractOrderFilledCancelledFetcher } from '../src/abstract/abstract_order_filled_cancelled_fetcher'; -import { OrderStateUtils } from '../src/order_state_utils'; - -import { chaiSetup } from './utils/chai_setup'; -import { testOrderFactory } from './utils/test_order_factory'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('OrderStateUtils', () => { - describe('#getOpenOrderStateAsync', () => { - const buildMockBalanceFetcher = (takerBalance: BigNumber): AbstractBalanceAndProxyAllowanceFetcher => { - const balanceFetcher = { - async getBalanceAsync(_assetData: string, _userAddress: string): Promise { - return takerBalance; - }, - async getProxyAllowanceAsync(_assetData: string, _userAddress: string): Promise { - return takerBalance; - }, - }; - return balanceFetcher; - }; - const buildMockOrderFilledFetcher = ( - filledAmount: BigNumber = new BigNumber(0), - cancelled: boolean = false, - ): AbstractOrderFilledCancelledFetcher => { - const orderFetcher = { - async getFilledTakerAmountAsync(_orderHash: string): Promise { - return filledAmount; - }, - async isOrderCancelledAsync(_signedOrder: SignedOrder): Promise { - return cancelled; - }, - }; - return orderFetcher; - }; - it('should have valid order state if order can be fully filled with small maker amount', async () => { - const makerAssetAmount = new BigNumber(10); - const takerAssetAmount = new BigNumber(10000000000000000); - const takerBalance = takerAssetAmount; - const orderFilledAmount = new BigNumber(0); - const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); - const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount); - const [signedOrder] = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerAssetAmount, - }, - 1, - ); - - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); - const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); - expect(orderState.isValid).to.eq(true); - }); - it('should be invalid when an order is partially filled where only a rounding error remains', async () => { - const makerAssetAmount = new BigNumber(1001); - const takerAssetAmount = new BigNumber(3); - const takerBalance = takerAssetAmount; - const orderFilledAmount = new BigNumber(2); - const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); - const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount); - const [signedOrder] = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerAssetAmount, - }, - 1, - ); - - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); - const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); - expect(orderState.isValid).to.eq(false); - }); - it('should be invalid when an order is cancelled', async () => { - const makerAssetAmount = new BigNumber(1000); - const takerAssetAmount = new BigNumber(2); - const takerBalance = takerAssetAmount; - const orderFilledAmount = new BigNumber(0); - const isCancelled = true; - const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); - const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount, isCancelled); - const [signedOrder] = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerAssetAmount, - }, - 1, - ); - - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); - const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); - expect(orderState.isValid).to.eq(false); - }); - it('should be invalid when an order is fully filled', async () => { - const makerAssetAmount = new BigNumber(1000); - const takerAssetAmount = new BigNumber(2); - const takerBalance = takerAssetAmount; - const orderFilledAmount = takerAssetAmount; - const isCancelled = false; - const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); - const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount, isCancelled); - const [signedOrder] = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerAssetAmount, - }, - 1, - ); - - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); - const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder); - expect(orderState.isValid).to.eq(false); - }); - it('should include the transactionHash in orderState if supplied in method invocation', async () => { - const makerAssetAmount = new BigNumber(10); - const takerAssetAmount = new BigNumber(10000000000000000); - const takerBalance = takerAssetAmount; - const orderFilledAmount = new BigNumber(0); - const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance); - const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount); - const [signedOrder] = testOrderFactory.generateTestSignedOrders( - { - makerAssetAmount, - takerAssetAmount, - }, - 1, - ); - - const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher); - const transactionHash = '0xdeadbeef'; - const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder, transactionHash); - expect(orderState.transactionHash).to.eq(transactionHash); - }); - }); -}); diff --git a/packages/order-utils/test/order_validation_utils_test.ts b/packages/order-utils/test/order_validation_utils_test.ts deleted file mode 100644 index d4d12a6a7f..0000000000 --- a/packages/order-utils/test/order_validation_utils_test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { OrderValidationUtils } from '../src/order_validation_utils'; - -import { chaiSetup } from './utils/chai_setup'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('OrderValidationUtils', () => { - describe('#isRoundingError', () => { - it('should return false if there is a rounding error of 0.1%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(999); - const target = new BigNumber(50); - // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - - it('should return false if there is a rounding of 0.09%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9991); - const target = new BigNumber(500); - // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - - it('should return true if there is a rounding error of 0.11%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9989); - const target = new BigNumber(500); - // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - - it('should return true if there is a rounding error > 0.1%', async () => { - const numerator = new BigNumber(3); - const denominator = new BigNumber(7); - const target = new BigNumber(10); - // rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67% - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - - it('should return false when there is no rounding error', async () => { - const numerator = new BigNumber(1); - const denominator = new BigNumber(2); - const target = new BigNumber(10); - - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - - it('should return false when there is rounding error <= 0.1%', async () => { - // randomly generated numbers - const numerator = new BigNumber(76564); - const denominator = new BigNumber(676373677); - const target = new BigNumber(105762562); - // rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) / - // (76564*105762562/676373677) = 0.0007% - const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - }); -});