aboutsummaryrefslogtreecommitdiffstats
path: root/src/order_watcher
diff options
context:
space:
mode:
Diffstat (limited to 'src/order_watcher')
-rw-r--r--src/order_watcher/event_watcher.ts15
-rw-r--r--src/order_watcher/order_state_watcher.ts108
2 files changed, 72 insertions, 51 deletions
diff --git a/src/order_watcher/event_watcher.ts b/src/order_watcher/event_watcher.ts
index c9e72281c..81529a98c 100644
--- a/src/order_watcher/event_watcher.ts
+++ b/src/order_watcher/event_watcher.ts
@@ -28,10 +28,8 @@ export class EventWatcher {
private _pollingIntervalMs: number;
private _intervalIdIfExists?: NodeJS.Timer;
private _lastEvents: Web3.LogEntry[] = [];
- private _numConfirmations: number;
- constructor(web3Wrapper: Web3Wrapper, pollingIntervalMs: undefined|number, numConfirmations: number) {
+ constructor(web3Wrapper: Web3Wrapper, pollingIntervalMs: undefined|number) {
this._web3Wrapper = web3Wrapper;
- this._numConfirmations = numConfirmations;
this._pollingIntervalMs = _.isUndefined(pollingIntervalMs) ?
DEFAULT_EVENT_POLLING_INTERVAL :
pollingIntervalMs;
@@ -67,16 +65,9 @@ export class EventWatcher {
this._lastEvents = pendingEvents;
}
private async _getEventsAsync(): Promise<Web3.LogEntry[]> {
- let latestBlock: BlockParamLiteral|number;
- if (this._numConfirmations === 0) {
- latestBlock = BlockParamLiteral.Pending;
- } else {
- const currentBlock = await this._web3Wrapper.getBlockNumberAsync();
- latestBlock = currentBlock - this._numConfirmations;
- }
const eventFilter = {
- fromBlock: latestBlock,
- toBlock: latestBlock,
+ fromBlock: BlockParamLiteral.Pending,
+ toBlock: BlockParamLiteral.Pending,
};
const events = await this._web3Wrapper.getLogsAsync(eventFilter);
return events;
diff --git a/src/order_watcher/order_state_watcher.ts b/src/order_watcher/order_state_watcher.ts
index 4866f8409..139f13fdf 100644
--- a/src/order_watcher/order_state_watcher.ts
+++ b/src/order_watcher/order_state_watcher.ts
@@ -1,6 +1,5 @@
import * as _ from 'lodash';
import {schemas} from '0x-json-schemas';
-import * as ethUtil from 'ethereumjs-util';
import {ZeroEx} from '../0x';
import {EventWatcher} from './event_watcher';
import {assert} from '../utils/assert';
@@ -15,13 +14,22 @@ import {
Web3Provider,
BlockParamLiteral,
LogWithDecodedArgs,
+ ContractEventArgs,
OnOrderStateChangeCallback,
OrderStateWatcherConfig,
+ ApprovalContractEventArgs,
+ TransferContractEventArgs,
+ LogFillContractEventArgs,
+ LogCancelContractEventArgs,
ExchangeEvents,
TokenEvents,
ZeroExError,
} from '../types';
import {Web3Wrapper} from '../web3_wrapper';
+import {TokenWrapper} from '../contract_wrappers/token_wrapper';
+import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
+import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
+import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
const DEFAULT_NUM_CONFIRMATIONS = 0;
@@ -44,26 +52,26 @@ interface OrderByOrderHash {
export class OrderStateWatcher {
private _orderByOrderHash: OrderByOrderHash = {};
private _dependentOrderHashes: DependentOrderHashes = {};
- private _web3Wrapper: Web3Wrapper;
private _callbackIfExistsAsync?: OnOrderStateChangeCallback;
private _eventWatcher: EventWatcher;
+ private _web3Wrapper: Web3Wrapper;
private _abiDecoder: AbiDecoder;
private _orderStateUtils: OrderStateUtils;
- private _numConfirmations: number;
+ private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
+ private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
constructor(
- web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, orderStateUtils: OrderStateUtils,
+ web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, token: TokenWrapper, exchange: ExchangeWrapper,
config?: OrderStateWatcherConfig,
) {
+ this._abiDecoder = abiDecoder;
this._web3Wrapper = web3Wrapper;
- const eventPollingIntervalMs = _.isUndefined(config) ? undefined : config.pollingIntervalMs;
- this._numConfirmations = _.isUndefined(config) ?
- DEFAULT_NUM_CONFIRMATIONS
- : config.numConfirmations;
- this._eventWatcher = new EventWatcher(
- this._web3Wrapper, eventPollingIntervalMs, this._numConfirmations,
+ const eventPollingIntervalMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
+ this._eventWatcher = new EventWatcher(web3Wrapper, eventPollingIntervalMs);
+ this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(token);
+ this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
+ this._orderStateUtils = new OrderStateUtils(
+ this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore,
);
- this._abiDecoder = abiDecoder;
- this._orderStateUtils = orderStateUtils;
}
/**
* Add an order to the orderStateWatcher. Before the order is added, it's
@@ -108,6 +116,11 @@ export class OrderStateWatcher {
* Ends an orderStateWatcher subscription.
*/
public unsubscribe(): void {
+ if (_.isUndefined(this._callbackIfExistsAsync)) {
+ throw new Error(ZeroExError.SubscriptionNotFound);
+ }
+ this._balanceAndProxyAllowanceLazyStore.deleteAll();
+ this._orderFilledCancelledLazyStore.deleteAll();
delete this._callbackIfExistsAsync;
this._eventWatcher.unsubscribe();
}
@@ -117,45 +130,68 @@ export class OrderStateWatcher {
if (!isLogDecoded) {
return; // noop
}
- // Unfortunately blockNumber is returned as a hex-encoded string, so we
- // convert it to a number here.
- const blockNumberBuff = ethUtil.toBuffer(maybeDecodedLog.blockNumber);
- const blockNumber = ethUtil.bufferToInt(blockNumberBuff);
-
- const decodedLog = maybeDecodedLog as LogWithDecodedArgs<any>;
+ const decodedLog = maybeDecodedLog as LogWithDecodedArgs<ContractEventArgs>;
let makerToken: string;
let makerAddress: string;
let orderHashesSet: Set<string>;
switch (decodedLog.event) {
case TokenEvents.Approval:
+ {
+ // Invalidate cache
+ const args = decodedLog.args as ApprovalContractEventArgs;
+ this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
+ // Revalidate orders
makerToken = decodedLog.address;
- makerAddress = decodedLog.args._owner;
+ makerAddress = args._owner;
orderHashesSet = _.get(this._dependentOrderHashes, [makerAddress, makerToken]);
if (!_.isUndefined(orderHashesSet)) {
const orderHashes = Array.from(orderHashesSet);
- await this._emitRevalidateOrdersAsync(orderHashes, blockNumber);
+ await this._emitRevalidateOrdersAsync(orderHashes);
}
break;
-
+ }
case TokenEvents.Transfer:
+ {
+ // Invalidate cache
+ const args = decodedLog.args as TransferContractEventArgs;
+ this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
+ this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._to);
+ // Revalidate orders
makerToken = decodedLog.address;
- makerAddress = decodedLog.args._from;
+ makerAddress = args._from;
orderHashesSet = _.get(this._dependentOrderHashes, [makerAddress, makerToken]);
if (!_.isUndefined(orderHashesSet)) {
const orderHashes = Array.from(orderHashesSet);
- await this._emitRevalidateOrdersAsync(orderHashes, blockNumber);
+ await this._emitRevalidateOrdersAsync(orderHashes);
}
break;
-
+ }
case ExchangeEvents.LogFill:
+ {
+ // Invalidate cache
+ const args = decodedLog.args as LogFillContractEventArgs;
+ this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
+ // Revalidate orders
+ const orderHash = args.orderHash;
+ const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
+ if (isOrderWatched) {
+ await this._emitRevalidateOrdersAsync([orderHash]);
+ }
+ break;
+ }
case ExchangeEvents.LogCancel:
- const orderHash = decodedLog.args.orderHash;
+ {
+ // Invalidate cache
+ const args = decodedLog.args as LogCancelContractEventArgs;
+ this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
+ // Revalidate orders
+ const orderHash = args.orderHash;
const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
if (isOrderWatched) {
- await this._emitRevalidateOrdersAsync([orderHash], blockNumber);
+ await this._emitRevalidateOrdersAsync([orderHash]);
}
break;
-
+ }
case ExchangeEvents.LogError:
return; // noop
@@ -163,22 +199,16 @@ export class OrderStateWatcher {
throw utils.spawnSwitchErr('decodedLog.event', decodedLog.event);
}
}
- private async _emitRevalidateOrdersAsync(orderHashes: string[], blockNumber: number): Promise<void> {
- const defaultBlock = this._numConfirmations === 0 ?
- BlockParamLiteral.Pending :
- blockNumber;
- const methodOpts = {
- defaultBlock,
- };
-
+ private async _emitRevalidateOrdersAsync(orderHashes: string[]): Promise<void> {
for (const orderHash of orderHashes) {
const signedOrder = this._orderByOrderHash[orderHash] as SignedOrder;
- const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder, methodOpts);
- if (!_.isUndefined(this._callbackIfExistsAsync)) {
- await this._callbackIfExistsAsync(orderState);
- } else {
+ // Most of these calls will never reach the network because the data is fetched from stores
+ // and only updated when cache is invalidated
+ const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder);
+ if (_.isUndefined(this._callbackIfExistsAsync)) {
break; // Unsubscribe was called
}
+ await this._callbackIfExistsAsync(orderState);
}
}
private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string) {