diff options
Diffstat (limited to 'packages')
11 files changed, 165 insertions, 32 deletions
diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 8be892215..65228b183 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -13,6 +13,10 @@ { "note": "Moved Web3.Provider to `@0xproject/types:Provider`", "pr": 501 + }, + { + "note": "Add `zeroEx.exchange.getOrderStateAsync` to allow obtaining current OrderState for a signedOrder", + "pr": 510 } ], "timestamp": 1523462196 diff --git a/packages/0x.js/src/abstract/balance_and_proxy_allowance_fetcher.ts b/packages/0x.js/src/abstract/balance_and_proxy_allowance_fetcher.ts new file mode 100644 index 000000000..c357f8447 --- /dev/null +++ b/packages/0x.js/src/abstract/balance_and_proxy_allowance_fetcher.ts @@ -0,0 +1,6 @@ +import { BigNumber } from '@0xproject/utils'; + +export abstract class BalanceAndProxyAllowanceFetcher { + public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>; + public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>; +} diff --git a/packages/0x.js/src/abstract/order_filled_cancelled_fetcher.ts b/packages/0x.js/src/abstract/order_filled_cancelled_fetcher.ts new file mode 100644 index 000000000..81ae04b9c --- /dev/null +++ b/packages/0x.js/src/abstract/order_filled_cancelled_fetcher.ts @@ -0,0 +1,6 @@ +import { BigNumber } from '@0xproject/utils'; + +export abstract class OrderFilledCancelledFetcher { + public abstract async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber>; + public abstract async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber>; +} diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts index 378ae8111..eacd3ebf0 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -13,6 +13,8 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; import { artifacts } from '../artifacts'; +import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher'; +import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher'; import { BlockRange, EventCallback, @@ -23,6 +25,7 @@ import { OrderAddresses, OrderCancellationRequest, OrderFillRequest, + OrderState, OrderTransactionOpts, OrderValues, ValidateOrderFillableOpts, @@ -30,6 +33,7 @@ import { import { assert } from '../utils/assert'; import { decorators } from '../utils/decorators'; import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator'; +import { OrderStateUtils } from '../utils/order_state_utils'; import { OrderValidationUtils } from '../utils/order_validation_utils'; import { utils } from '../utils/utils'; @@ -41,7 +45,6 @@ import { LogErrorContractEventArgs, } from './generated/exchange'; import { TokenWrapper } from './token_wrapper'; - const SHOULD_VALIDATE_BY_DEFAULT = true; interface ExchangeContractErrCodesToMsgs { @@ -874,6 +877,22 @@ export class ExchangeWrapper extends ContractWrapper { } } /** + * Gets the latest OrderState of a signedOrder + * @param signedOrder The signedOrder + * @param stateLayer Optional, desired blockchain state layer (defaults to latest). + * @return OrderState of the signedOrder + */ + public async getOrderStateAsync(signedOrder: SignedOrder, stateLayer: BlockParamLiteral = BlockParamLiteral.Latest): Promise<OrderState> { + const simpleBalanceAndProxyAllowanceFetcher = new SimpleBalanceAndProxyAllowanceFetcher( + this._tokenWrapper, + stateLayer, + ); + const simpleOrderFilledCancelledFetcher = new SimpleOrderFilledCancelledFetcher(this, stateLayer); + const orderStateUtils = new OrderStateUtils(simpleBalanceAndProxyAllowanceFetcher, simpleOrderFilledCancelledFetcher); + const orderState = orderStateUtils.getOrderStateAsync(signedOrder); + return orderState; + } + /** * Returns the ZRX token address used by the exchange contract. * @return Address of ZRX token */ diff --git a/packages/0x.js/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts b/packages/0x.js/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts new file mode 100644 index 000000000..c00dba5cf --- /dev/null +++ b/packages/0x.js/src/fetchers/simple_balance_and_proxy_allowance_fetcher.ts @@ -0,0 +1,28 @@ +import { BlockParamLiteral } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; + +import {BalanceAndProxyAllowanceFetcher} from '../abstract/balance_and_proxy_allowance_fetcher'; +import {TokenWrapper} from '../contract_wrappers/token_wrapper'; + +export class SimpleBalanceAndProxyAllowanceFetcher implements BalanceAndProxyAllowanceFetcher { + private _tokenWrapper: TokenWrapper; + private _defaultBlock: BlockParamLiteral; + constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { + this._tokenWrapper = token; + this._defaultBlock = defaultBlock; + } + public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const balance = this._tokenWrapper.getBalanceAsync(tokenAddress, userAddress, methodOpts); + return balance; + } + public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const proxyAllowance = this._tokenWrapper.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts); + return proxyAllowance; + } +} diff --git a/packages/0x.js/src/fetchers/simple_order_filled_cancelled_fetcher.ts b/packages/0x.js/src/fetchers/simple_order_filled_cancelled_fetcher.ts new file mode 100644 index 000000000..1c8aec1a1 --- /dev/null +++ b/packages/0x.js/src/fetchers/simple_order_filled_cancelled_fetcher.ts @@ -0,0 +1,28 @@ +import { BlockParamLiteral } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; + +import {OrderFilledCancelledFetcher} from '../abstract/order_filled_cancelled_fetcher'; +import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper'; + +export class SimpleOrderFilledCancelledFetcher implements OrderFilledCancelledFetcher { + private _exchangeWrapper: ExchangeWrapper; + private _defaultBlock: BlockParamLiteral; + constructor(exchange: ExchangeWrapper, defaultBlock: BlockParamLiteral) { + this._exchangeWrapper = exchange; + this._defaultBlock = defaultBlock; + } + public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const filledTakerAmount = this._exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts); + return filledTakerAmount; + } + public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> { + const methodOpts = { + defaultBlock: this._defaultBlock, + }; + const cancelledTakerAmount = this._exchangeWrapper.getCancelledTakerAmountAsync(orderHash, methodOpts); + return cancelledTakerAmount; + } +} diff --git a/packages/0x.js/src/order_watcher/order_state_watcher.ts b/packages/0x.js/src/order_watcher/order_state_watcher.ts index 0aa0c33bd..a9df8ac9d 100644 --- a/packages/0x.js/src/order_watcher/order_state_watcher.ts +++ b/packages/0x.js/src/order_watcher/order_state_watcher.ts @@ -87,7 +87,7 @@ export class OrderStateWatcher { _.isUndefined(config) || _.isUndefined(config.stateLayer) ? BlockParamLiteral.Latest : config.stateLayer; this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs, stateLayer); this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(token, stateLayer); - this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange); + this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange, stateLayer); this._orderStateUtils = new OrderStateUtils( this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore, @@ -131,7 +131,7 @@ export class OrderStateWatcher { } delete this._orderByOrderHash[orderHash]; delete this._orderStateByOrderHashCache[orderHash]; - const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper; + const exchange = (this._orderFilledCancelledLazyStore as any)._exchangeWrapper as ExchangeWrapper; const zrxTokenAddress = exchange.getZRXTokenAddress(); this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash); @@ -374,7 +374,7 @@ export class OrderStateWatcher { } } private _getZRXTokenAddress(): string { - const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper; + const exchange = (this._orderFilledCancelledLazyStore as any)._exchangeWrapper as ExchangeWrapper; const zrxTokenAddress = exchange.getZRXTokenAddress(); return zrxTokenAddress; } diff --git a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts index ede1319fe..c8395415e 100644 --- a/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts +++ b/packages/0x.js/src/stores/balance_proxy_allowance_lazy_store.ts @@ -3,12 +3,13 @@ import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import { TokenWrapper } from '../contract_wrappers/token_wrapper'; +import { BalanceAndProxyAllowanceFetcher } from '../abstract/balance_and_proxy_allowance_fetcher'; /** * Copy on read store for balances/proxyAllowances of tokens/accounts */ -export class BalanceAndProxyAllowanceLazyStore { - private _token: TokenWrapper; +export class BalanceAndProxyAllowanceLazyStore implements BalanceAndProxyAllowanceFetcher { + private _tokenWrapper: TokenWrapper; private _defaultBlock: BlockParamLiteral; private _balance: { [tokenAddress: string]: { @@ -21,7 +22,7 @@ export class BalanceAndProxyAllowanceLazyStore { }; }; constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { - this._token = token; + this._tokenWrapper = token; this._defaultBlock = defaultBlock; this._balance = {}; this._proxyAllowance = {}; @@ -31,7 +32,7 @@ export class BalanceAndProxyAllowanceLazyStore { const methodOpts = { defaultBlock: this._defaultBlock, }; - const balance = await this._token.getBalanceAsync(tokenAddress, userAddress, methodOpts); + const balance = await this._tokenWrapper.getBalanceAsync(tokenAddress, userAddress, methodOpts); this.setBalance(tokenAddress, userAddress, balance); } const cachedBalance = this._balance[tokenAddress][userAddress]; @@ -59,7 +60,7 @@ export class BalanceAndProxyAllowanceLazyStore { const methodOpts = { defaultBlock: this._defaultBlock, }; - const proxyAllowance = await this._token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts); + const proxyAllowance = await this._tokenWrapper.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts); this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance); } const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress]; diff --git a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts index 0a0d93406..7f3da6e1d 100644 --- a/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts +++ b/packages/0x.js/src/stores/order_filled_cancelled_lazy_store.ts @@ -3,29 +3,32 @@ import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; +import { OrderFilledCancelledFetcher } from '../abstract/order_filled_cancelled_fetcher'; /** * Copy on read store for filled/cancelled taker amounts */ -export class OrderFilledCancelledLazyStore { - private _exchange: ExchangeWrapper; +export class OrderFilledCancelledLazyStore implements OrderFilledCancelledFetcher { + private _exchangeWrapper: ExchangeWrapper; + private _defaultBlock: BlockParamLiteral; private _filledTakerAmount: { [orderHash: string]: BigNumber; }; private _cancelledTakerAmount: { [orderHash: string]: BigNumber; }; - constructor(exchange: ExchangeWrapper) { - this._exchange = exchange; + constructor(exchange: ExchangeWrapper, defaultBlock: BlockParamLiteral) { + this._exchangeWrapper = exchange; + this._defaultBlock = defaultBlock; this._filledTakerAmount = {}; this._cancelledTakerAmount = {}; } public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> { if (_.isUndefined(this._filledTakerAmount[orderHash])) { const methodOpts = { - defaultBlock: BlockParamLiteral.Pending, + defaultBlock: this._defaultBlock, }; - const filledTakerAmount = await this._exchange.getFilledTakerAmountAsync(orderHash, methodOpts); + const filledTakerAmount = await this._exchangeWrapper.getFilledTakerAmountAsync(orderHash, methodOpts); this.setFilledTakerAmount(orderHash, filledTakerAmount); } const cachedFilled = this._filledTakerAmount[orderHash]; @@ -40,9 +43,9 @@ export class OrderFilledCancelledLazyStore { public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> { if (_.isUndefined(this._cancelledTakerAmount[orderHash])) { const methodOpts = { - defaultBlock: BlockParamLiteral.Pending, + defaultBlock: this._defaultBlock, }; - const cancelledTakerAmount = await this._exchange.getCancelledTakerAmountAsync(orderHash, methodOpts); + const cancelledTakerAmount = await this._exchangeWrapper.getCancelledTakerAmountAsync(orderHash, methodOpts); this.setCancelledTakerAmount(orderHash, cancelledTakerAmount); } const cachedCancelled = this._cancelledTakerAmount[orderHash]; diff --git a/packages/0x.js/src/utils/order_state_utils.ts b/packages/0x.js/src/utils/order_state_utils.ts index 38189443b..e15ff6bc9 100644 --- a/packages/0x.js/src/utils/order_state_utils.ts +++ b/packages/0x.js/src/utils/order_state_utils.ts @@ -4,16 +4,16 @@ import * as _ from 'lodash'; import { ZeroEx } from '../0x'; import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; +import { BalanceAndProxyAllowanceFetcher } from '../abstract/balance_and_proxy_allowance_fetcher'; +import { OrderFilledCancelledFetcher } from '../abstract/order_filled_cancelled_fetcher'; import { RemainingFillableCalculator } from '../order_watcher/remaining_fillable_calculator'; -import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store'; -import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store'; import { ExchangeContractErrs, OrderRelevantState, OrderState, OrderStateInvalid, OrderStateValid } from '../types'; const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001; export class OrderStateUtils { - private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore; - private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore; + private _balanceAndProxyAllowanceFetcher: BalanceAndProxyAllowanceFetcher; + private _orderFilledCancelledFetcher: OrderFilledCancelledFetcher; private static _validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void { const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add( orderRelevantState.filledTakerTokenAmount, @@ -49,11 +49,11 @@ export class OrderStateUtils { } } constructor( - balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore, - orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore, + balanceAndProxyAllowanceFetcher: BalanceAndProxyAllowanceFetcher, + orderFilledCancelledFetcher: OrderFilledCancelledFetcher, ) { - this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore; - this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore; + this._balanceAndProxyAllowanceFetcher = balanceAndProxyAllowanceFetcher; + this._orderFilledCancelledFetcher = orderFilledCancelledFetcher; } public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> { const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder); @@ -80,27 +80,27 @@ export class OrderStateUtils { // If we pass it from the instantiator - there is no opportunity to get it there // because JS doesn't support async constructors. // Moreover - it's cached under the hood so it's equivalent to an async constructor. - const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper; + const exchange = (this._orderFilledCancelledFetcher as any)._exchangeWrapper as ExchangeWrapper; const zrxTokenAddress = exchange.getZRXTokenAddress(); const orderHash = ZeroEx.getOrderHashHex(signedOrder); - const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync( + const makerBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync( signedOrder.makerTokenAddress, signedOrder.maker, ); - const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( + const makerProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( signedOrder.makerTokenAddress, signedOrder.maker, ); - const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync( + const makerFeeBalance = await this._balanceAndProxyAllowanceFetcher.getBalanceAsync( zrxTokenAddress, signedOrder.maker, ); - const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync( + const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceFetcher.getProxyAllowanceAsync( zrxTokenAddress, signedOrder.maker, ); - const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash); - const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync( + const filledTakerTokenAmount = await this._orderFilledCancelledFetcher.getFilledTakerAmountAsync(orderHash); + const cancelledTakerTokenAmount = await this._orderFilledCancelledFetcher.getCancelledTakerAmountAsync( orderHash, ); const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash); diff --git a/packages/0x.js/test/exchange_wrapper_test.ts b/packages/0x.js/test/exchange_wrapper_test.ts index cd74af5a1..65f4e8251 100644 --- a/packages/0x.js/test/exchange_wrapper_test.ts +++ b/packages/0x.js/test/exchange_wrapper_test.ts @@ -14,6 +14,7 @@ import { LogFillContractEventArgs, OrderCancellationRequest, OrderFillRequest, + OrderState, SignedOrder, Token, ZeroEx, @@ -1154,4 +1155,41 @@ describe('ExchangeWrapper', () => { expect(args.maker).to.be.equal(differentMakerAddress); }); }); + describe('#getOrderStateAsync', () => { + let maker: string; + let taker: string; + let makerToken: Token; + let takerToken: Token; + let signedOrder: SignedOrder; + let orderState: OrderState; + const fillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(5), constants.ZRX_DECIMALS); + before(async () => { + [, maker, taker] = userAddresses; + tokens = await zeroEx.tokenRegistry.getTokensAsync(); + [makerToken, takerToken] = tokenUtils.getDummyTokens(); + }); + it('should report orderStateValid when order is fillable', async () => { + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, + ); + orderState = await zeroEx.exchange.getOrderStateAsync(signedOrder); + expect(orderState.isValid).to.be.true(); + }); + it('should report orderStateInvalid when maker allowance set to 0', async () => { + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerToken.address, + takerToken.address, + maker, + taker, + fillableAmount, + ); + await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0)); + orderState = await zeroEx.exchange.getOrderStateAsync(signedOrder); + expect(orderState.isValid).to.be.false(); + }); + }); }); // tslint:disable:max-file-line-count |