Removed the order-watcher files that were accidentally added
This commit is contained in:
@@ -1,607 +0,0 @@
|
||||
[
|
||||
{
|
||||
"version": "4.0.18",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Pass `signedOrder.exchangeAddress` to `signatureUtils.isValidSignatureAsync` when adding an order to watcher.",
|
||||
"pr": 2017
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1565296576,
|
||||
"version": "4.0.17",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1564604963,
|
||||
"version": "4.0.16",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1563957393,
|
||||
"version": "4.0.15",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1563193019,
|
||||
"version": "4.0.14",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1563047529,
|
||||
"version": "4.0.13",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1563006338,
|
||||
"version": "4.0.12",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1558712885,
|
||||
"version": "4.0.11",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1557961111,
|
||||
"version": "4.0.10",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.9",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1557799313
|
||||
},
|
||||
{
|
||||
"version": "4.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix race-condition bug due to async callback modifying shared state",
|
||||
"pr": 1789
|
||||
},
|
||||
{
|
||||
"note": "Fix bug where WETH deposit/withdrawal events would not trigger an order state update",
|
||||
"pr": 1809
|
||||
}
|
||||
],
|
||||
"timestamp": 1557507213
|
||||
},
|
||||
{
|
||||
"version": "4.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1554997931
|
||||
},
|
||||
{
|
||||
"timestamp": 1553183790,
|
||||
"version": "4.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Update websocket from ^1.0.25 to ^1.0.26",
|
||||
"pr": 1685
|
||||
},
|
||||
{
|
||||
"note": "Fix issue where ERC721 Approval events could cause a lookup on undefined object",
|
||||
"pr": 1692
|
||||
},
|
||||
{
|
||||
"note": "Fix race-condition bugs due to async event callbacks modifying shared state",
|
||||
"pr": 1718
|
||||
},
|
||||
{
|
||||
"note": "Run Web3ProviderEngine without excess block polling",
|
||||
"pr": 1695
|
||||
}
|
||||
],
|
||||
"timestamp": 1553091633
|
||||
},
|
||||
{
|
||||
"timestamp": 1551479279,
|
||||
"version": "4.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1551299797,
|
||||
"version": "4.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1551220833,
|
||||
"version": "4.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add support for EIP1193 providers & Web3.js providers >= 1.0-beta.38",
|
||||
"pr": 1627
|
||||
},
|
||||
{
|
||||
"note": "Update provider params to type SupportedProvider which outlines all supported providers",
|
||||
"pr": 1627
|
||||
}
|
||||
],
|
||||
"timestamp": 1551130135
|
||||
},
|
||||
{
|
||||
"timestamp": 1549733923,
|
||||
"version": "3.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1549547375
|
||||
},
|
||||
{
|
||||
"timestamp": 1549504360,
|
||||
"version": "3.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1549452781,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Upgrade the bignumber.js to v8.0.2",
|
||||
"pr": 1517
|
||||
}
|
||||
],
|
||||
"timestamp": 1549373905
|
||||
},
|
||||
{
|
||||
"timestamp": 1547747677,
|
||||
"version": "2.4.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1547561734,
|
||||
"version": "2.4.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1547225310,
|
||||
"version": "2.4.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.4.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add support for `MultiAssetProxy`",
|
||||
"pr": 1363
|
||||
}
|
||||
],
|
||||
"timestamp": 1547040760
|
||||
},
|
||||
{
|
||||
"version": "2.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added a WebSocket interface to OrderWatcher so that it can be used by a client written in any language",
|
||||
"pr": 1427
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.2.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1544739608
|
||||
},
|
||||
{
|
||||
"version": "2.2.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1544570656
|
||||
},
|
||||
{
|
||||
"timestamp": 1543401373,
|
||||
"version": "2.2.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1542821676,
|
||||
"version": "2.2.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.2.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix the bug when order watcher was throwing an error on order removal when maker token was ZRX",
|
||||
"pr": 1259
|
||||
}
|
||||
],
|
||||
"timestamp": 1542208198
|
||||
},
|
||||
{
|
||||
"version": "2.2.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Start jsonRpcRequestId at 1, not 0 as 0 breaks the web3.js websocket RPC provider",
|
||||
"pr": 1227
|
||||
},
|
||||
{
|
||||
"note": "Fix the bug when order watcher was trying to convert undefined to an object in case of CancelUpTo event"
|
||||
}
|
||||
],
|
||||
"timestamp": 1542134075
|
||||
},
|
||||
{
|
||||
"timestamp": 1542028948,
|
||||
"version": "2.2.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1541740904
|
||||
},
|
||||
{
|
||||
"version": "2.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added getStats function and returns a Stats object",
|
||||
"pr": 1118
|
||||
},
|
||||
{
|
||||
"note": "Updated to use new modularized artifacts and the latest version of @0xproject/contract-wrappers. Constructor has a new optional `contractAddresses` parameter.",
|
||||
"pr": 1105
|
||||
}
|
||||
],
|
||||
"timestamp": 1539871071
|
||||
},
|
||||
{
|
||||
"version": "2.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1538693146
|
||||
},
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Export ExpirationWatcher",
|
||||
"pr": 1097
|
||||
}
|
||||
],
|
||||
"timestamp": 1538157789
|
||||
},
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fixes dropped events issue by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too.",
|
||||
"pr": 1080
|
||||
},
|
||||
{
|
||||
"note": "Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it",
|
||||
"pr": 1080
|
||||
},
|
||||
{
|
||||
"note": "Add `transactionHash` to `OrderState` emitted by `OrderWatcher` subscriptions if the order's state change originated from a transaction.",
|
||||
"pr": 1087
|
||||
}
|
||||
],
|
||||
"timestamp": 1537907159
|
||||
},
|
||||
{
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1537875740
|
||||
},
|
||||
{
|
||||
"version": "1.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1537541580
|
||||
},
|
||||
{
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Drastically reduce the bundle size by removing unused parts of included contract artifacts."
|
||||
}
|
||||
],
|
||||
"timestamp": 1537369748
|
||||
},
|
||||
{
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add ZRX & WETH mainnet contract addresses into the included artifacts"
|
||||
}
|
||||
],
|
||||
"timestamp": 1537265493
|
||||
},
|
||||
{
|
||||
"timestamp": 1536142250,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix missing `BlockParamLiteral` type import issue"
|
||||
}
|
||||
],
|
||||
"timestamp": 1535377027
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Export types: `ExchangeContractErrs`, `OrderRelevantState`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload`",
|
||||
"pr": 924
|
||||
},
|
||||
{
|
||||
"note": "Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order`",
|
||||
"pr": 924
|
||||
}
|
||||
],
|
||||
"timestamp": 1535133899
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1534210131
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fixed bug caused by importing non-existent dep"
|
||||
}
|
||||
],
|
||||
"timestamp": 1532619515
|
||||
},
|
||||
{
|
||||
"version": "1.0.1-rc.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1532605697
|
||||
},
|
||||
{
|
||||
"timestamp": 1532357734,
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1532043000,
|
||||
"version": "1.0.0-rc.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add support for ERC721 event watching and Exchange V2 events",
|
||||
"pr": 887
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1531919263,
|
||||
"version": "0.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.0.7",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Switch out simple getLogs polling with ethereumjs-blockstream",
|
||||
"pr": 825
|
||||
},
|
||||
{
|
||||
"note": "Do not stop subscription if error is encountered",
|
||||
"pr": 825
|
||||
},
|
||||
{
|
||||
"note": "Fixed a bug that caused the incorrect block to be fetched via JSON-RPC within Blockstream",
|
||||
"pr": 875
|
||||
},
|
||||
{
|
||||
"note": "Remove stateLayer config from OrderWatcher. It now always operates on the latest block",
|
||||
"pr": 875
|
||||
}
|
||||
],
|
||||
"timestamp": 1531149657
|
||||
},
|
||||
{
|
||||
"timestamp": 1529397769,
|
||||
"version": "0.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527617805,
|
||||
"version": "0.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527617227,
|
||||
"version": "0.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527616612,
|
||||
"version": "0.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527008794,
|
||||
"version": "0.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1527008794,
|
||||
"version": "0.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Moved OrderWatcher out of 0x.js package",
|
||||
"pr": 579
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@@ -1,520 +0,0 @@
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
import { ContractAddresses } from '@0x/contract-addresses';
|
||||
import * as artifacts from '@0x/contract-artifacts';
|
||||
import {
|
||||
AssetBalanceAndProxyAllowanceFetcher,
|
||||
ContractWrappers,
|
||||
ERC20TokenApprovalEventArgs,
|
||||
ERC20TokenEventArgs,
|
||||
ERC20TokenEvents,
|
||||
ERC20TokenTransferEventArgs,
|
||||
ERC721TokenApprovalEventArgs,
|
||||
ERC721TokenApprovalForAllEventArgs,
|
||||
ERC721TokenEventArgs,
|
||||
ERC721TokenEvents,
|
||||
ERC721TokenTransferEventArgs,
|
||||
ExchangeCancelEventArgs,
|
||||
ExchangeCancelUpToEventArgs,
|
||||
ExchangeEventArgs,
|
||||
ExchangeEvents,
|
||||
ExchangeFillEventArgs,
|
||||
OrderFilledCancelledFetcher,
|
||||
WETH9DepositEventArgs,
|
||||
WETH9EventArgs,
|
||||
WETH9Events,
|
||||
WETH9WithdrawalEventArgs,
|
||||
} from '@0x/contract-wrappers';
|
||||
import { schemas } from '@0x/json-schemas';
|
||||
import {
|
||||
assetDataUtils,
|
||||
BalanceAndProxyAllowanceLazyStore,
|
||||
OrderFilledCancelledLazyStore,
|
||||
orderHashUtils,
|
||||
OrderStateUtils,
|
||||
} from '@0x/order-utils';
|
||||
import { AssetProxyId, ExchangeContractErrs, OrderState, SignedOrder, Stats } from '@0x/types';
|
||||
import { errorUtils, intervalUtils, providerUtils } from '@0x/utils';
|
||||
import {
|
||||
BlockParamLiteral,
|
||||
LogEntryEvent,
|
||||
LogWithDecodedArgs,
|
||||
SupportedProvider,
|
||||
ZeroExProvider,
|
||||
} from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import { Lock } from 'semaphore-async-await';
|
||||
|
||||
import { orderWatcherPartialConfigSchema } from '../schemas/order_watcher_partial_config_schema';
|
||||
import { OnOrderStateChangeCallback, OrderWatcherConfig, OrderWatcherError } from '../types';
|
||||
import { assert } from '../utils/assert';
|
||||
|
||||
import { CollisionResistanceAbiDecoder } from './collision_resistant_abi_decoder';
|
||||
import { DependentOrderHashesTracker } from './dependent_order_hashes_tracker';
|
||||
import { EventWatcher } from './event_watcher';
|
||||
import { ExpirationWatcher } from './expiration_watcher';
|
||||
|
||||
const MILLISECONDS_IN_A_SECOND = 1000;
|
||||
|
||||
type ContractEventArgs = WETH9EventArgs | ExchangeEventArgs | ERC20TokenEventArgs | ERC721TokenEventArgs;
|
||||
|
||||
interface OrderByOrderHash {
|
||||
[orderHash: string]: SignedOrder;
|
||||
}
|
||||
|
||||
interface OrderStateByOrderHash {
|
||||
[orderHash: string]: OrderState;
|
||||
}
|
||||
|
||||
const DEFAULT_ORDER_WATCHER_CONFIG: OrderWatcherConfig = {
|
||||
orderExpirationCheckingIntervalMs: 50,
|
||||
eventPollingIntervalMs: 200,
|
||||
expirationMarginMs: 0,
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
cleanupJobIntervalMs: 1000 * 60 * 60, // 1h
|
||||
isVerbose: true,
|
||||
};
|
||||
const STATE_LAYER = BlockParamLiteral.Latest;
|
||||
|
||||
/**
|
||||
* This class includes all the functionality related to watching a set of orders
|
||||
* for potential changes in order validity/fillability. The orderWatcher notifies
|
||||
* the subscriber of these changes so that a final decision can be made on whether
|
||||
* the order should be deemed invalid.
|
||||
*/
|
||||
export class OrderWatcher {
|
||||
private readonly _dependentOrderHashesTracker: DependentOrderHashesTracker;
|
||||
private readonly _orderStateByOrderHashCache: OrderStateByOrderHash = {};
|
||||
private readonly _orderByOrderHash: OrderByOrderHash = {};
|
||||
private readonly _lock = new Lock();
|
||||
private readonly _eventWatcher: EventWatcher;
|
||||
private readonly _provider: ZeroExProvider;
|
||||
private readonly _collisionResistantAbiDecoder: CollisionResistanceAbiDecoder;
|
||||
private readonly _expirationWatcher: ExpirationWatcher;
|
||||
private readonly _orderStateUtils: OrderStateUtils;
|
||||
private readonly _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
||||
private readonly _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
||||
private readonly _cleanupJobInterval: number;
|
||||
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
|
||||
private _callbackIfExists?: OnOrderStateChangeCallback;
|
||||
/**
|
||||
* Instantiate a new OrderWatcher
|
||||
* @param supportedProvider Web3 provider to use for JSON RPC calls
|
||||
* @param networkId NetworkId to watch orders on
|
||||
* @param contractAddresses Optional contract addresses. Defaults to known
|
||||
* addresses based on networkId.
|
||||
* @param partialConfig Optional configurations
|
||||
*/
|
||||
constructor(
|
||||
supportedProvider: SupportedProvider,
|
||||
networkId: number,
|
||||
contractAddresses?: ContractAddresses,
|
||||
partialConfig: Partial<OrderWatcherConfig> = DEFAULT_ORDER_WATCHER_CONFIG,
|
||||
) {
|
||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||
assert.isNumber('networkId', networkId);
|
||||
assert.doesConformToSchema('partialConfig', partialConfig, orderWatcherPartialConfigSchema);
|
||||
const config = {
|
||||
...DEFAULT_ORDER_WATCHER_CONFIG,
|
||||
...partialConfig,
|
||||
};
|
||||
|
||||
this._provider = provider;
|
||||
this._collisionResistantAbiDecoder = new CollisionResistanceAbiDecoder(
|
||||
artifacts.ERC20Token.compilerOutput.abi,
|
||||
artifacts.ERC721Token.compilerOutput.abi,
|
||||
[artifacts.WETH9.compilerOutput.abi, artifacts.Exchange.compilerOutput.abi],
|
||||
);
|
||||
const contractWrappers = new ContractWrappers(provider, {
|
||||
networkId,
|
||||
// Note(albrow): We let the contract-wrappers package handle
|
||||
// default values for contractAddresses.
|
||||
contractAddresses,
|
||||
});
|
||||
this._eventWatcher = new EventWatcher(provider, config.eventPollingIntervalMs, config.isVerbose);
|
||||
const balanceAndProxyAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher(
|
||||
contractWrappers.erc20Token,
|
||||
contractWrappers.erc721Token,
|
||||
STATE_LAYER,
|
||||
);
|
||||
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
balanceAndProxyAllowanceFetcher,
|
||||
);
|
||||
const orderFilledCancelledFetcher = new OrderFilledCancelledFetcher(contractWrappers.exchange, STATE_LAYER);
|
||||
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(orderFilledCancelledFetcher);
|
||||
this._orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher);
|
||||
const expirationMarginIfExistsMs = config === undefined ? undefined : config.expirationMarginMs;
|
||||
this._expirationWatcher = new ExpirationWatcher(
|
||||
expirationMarginIfExistsMs,
|
||||
config.orderExpirationCheckingIntervalMs,
|
||||
);
|
||||
this._cleanupJobInterval = config.cleanupJobIntervalMs;
|
||||
const zrxTokenAddress = assetDataUtils.decodeERC20AssetData(orderFilledCancelledFetcher.getZRXAssetData())
|
||||
.tokenAddress;
|
||||
this._dependentOrderHashesTracker = new DependentOrderHashesTracker(zrxTokenAddress);
|
||||
}
|
||||
/**
|
||||
* Add an order to the orderWatcher. Before the order is added, it's
|
||||
* signature is verified.
|
||||
* @param signedOrder The order you wish to start watching.
|
||||
*/
|
||||
public async addOrderAsync(signedOrder: SignedOrder): Promise<void> {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
await assert.isValidSignatureAsync(
|
||||
this._provider,
|
||||
orderHash,
|
||||
signedOrder.signature,
|
||||
signedOrder.makerAddress,
|
||||
signedOrder.exchangeAddress,
|
||||
);
|
||||
|
||||
const expirationUnixTimestampMs = signedOrder.expirationTimeSeconds.times(MILLISECONDS_IN_A_SECOND);
|
||||
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
||||
|
||||
this._orderByOrderHash[orderHash] = signedOrder;
|
||||
this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder);
|
||||
|
||||
const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData];
|
||||
_.each(orderAssetDatas, assetData => this._addAssetDataToAbiDecoder(assetData));
|
||||
}
|
||||
/**
|
||||
* Removes an order from the orderWatcher
|
||||
* @param orderHash The orderHash of the order you wish to stop watching.
|
||||
*/
|
||||
public removeOrder(orderHash: string): void {
|
||||
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
||||
const signedOrder = this._orderByOrderHash[orderHash];
|
||||
if (signedOrder === undefined) {
|
||||
return; // noop
|
||||
}
|
||||
this._dependentOrderHashesTracker.removeFromDependentOrderHashes(signedOrder);
|
||||
delete this._orderByOrderHash[orderHash];
|
||||
this._expirationWatcher.removeOrder(orderHash);
|
||||
delete this._orderStateByOrderHashCache[orderHash];
|
||||
}
|
||||
/**
|
||||
* Starts an orderWatcher subscription. The callback will be called every time a watched order's
|
||||
* backing blockchain state has changed. This is a call-to-action for the caller to re-validate the order.
|
||||
* @param callback Receives the orderHash of the order that should be re-validated, together
|
||||
* with all the order-relevant blockchain state needed to re-validate the order.
|
||||
*/
|
||||
public subscribe(callback: OnOrderStateChangeCallback): void {
|
||||
assert.isFunction('callback', callback);
|
||||
if (this._callbackIfExists !== undefined) {
|
||||
throw new Error(OrderWatcherError.SubscriptionAlreadyPresent);
|
||||
}
|
||||
this._callbackIfExists = callback;
|
||||
this._eventWatcher.subscribe(
|
||||
this._addLockToCallbackAsync.bind(this, this._onEventWatcherCallbackAsync.bind(this)),
|
||||
);
|
||||
this._expirationWatcher.subscribe(this._addLockToCallbackAsync.bind(this, this._onOrderExpired.bind(this)));
|
||||
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||
this._addLockToCallbackAsync.bind(this, this._cleanupAsync.bind(this)),
|
||||
this._cleanupJobInterval,
|
||||
(err: Error) => {
|
||||
this.unsubscribe();
|
||||
callback(err);
|
||||
},
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Ends an orderWatcher subscription.
|
||||
*/
|
||||
public unsubscribe(): void {
|
||||
if (this._callbackIfExists === undefined || this._cleanupJobIntervalIdIfExists === undefined) {
|
||||
throw new Error(OrderWatcherError.SubscriptionNotFound);
|
||||
}
|
||||
this._balanceAndProxyAllowanceLazyStore.deleteAll();
|
||||
this._orderFilledCancelledLazyStore.deleteAll();
|
||||
delete this._callbackIfExists;
|
||||
this._eventWatcher.unsubscribe();
|
||||
this._expirationWatcher.unsubscribe();
|
||||
intervalUtils.clearAsyncExcludingInterval(this._cleanupJobIntervalIdIfExists);
|
||||
}
|
||||
/**
|
||||
* Gets statistics of the OrderWatcher Instance.
|
||||
*/
|
||||
public getStats(): Stats {
|
||||
return {
|
||||
orderCount: _.size(this._orderByOrderHash),
|
||||
};
|
||||
}
|
||||
private async _addLockToCallbackAsync(cbAsync: any, ...params: any[]): Promise<void> {
|
||||
await this._lock.acquire();
|
||||
try {
|
||||
await cbAsync(...params);
|
||||
await this._lock.release();
|
||||
} catch (err) {
|
||||
// Make sure to releasee the lock if an error is thrown
|
||||
await this._lock.release();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
private async _cleanupAsync(): Promise<void> {
|
||||
for (const orderHash of _.keys(this._orderByOrderHash)) {
|
||||
this._cleanupOrderRelatedState(orderHash);
|
||||
await this._emitRevalidateOrdersAsync([orderHash]);
|
||||
}
|
||||
}
|
||||
private _addAssetDataToAbiDecoder(assetData: string): void {
|
||||
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||
if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
|
||||
this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress);
|
||||
} else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
|
||||
this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress);
|
||||
} else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
|
||||
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||
this._addAssetDataToAbiDecoder(nestedAssetDataElement),
|
||||
);
|
||||
}
|
||||
}
|
||||
private _deleteLazyStoreBalance(assetData: string, userAddress: string): void {
|
||||
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||
switch (assetProxyId) {
|
||||
case AssetProxyId.ERC20:
|
||||
case AssetProxyId.ERC721:
|
||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(assetData, userAddress);
|
||||
break;
|
||||
case AssetProxyId.MultiAsset:
|
||||
const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||
this._deleteLazyStoreBalance(nestedAssetDataElement, userAddress),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private _deleteLazyStoreProxyAllowance(assetData: string, userAddress: string): void {
|
||||
const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
|
||||
switch (assetProxyId) {
|
||||
case AssetProxyId.ERC20:
|
||||
case AssetProxyId.ERC721:
|
||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(assetData, userAddress);
|
||||
break;
|
||||
case AssetProxyId.MultiAsset:
|
||||
const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||
_.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
|
||||
this._deleteLazyStoreProxyAllowance(nestedAssetDataElement, userAddress),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private _cleanupOrderRelatedState(orderHash: string): void {
|
||||
const signedOrder = this._orderByOrderHash[orderHash];
|
||||
|
||||
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash);
|
||||
this._orderFilledCancelledLazyStore.deleteIsCancelled(orderHash);
|
||||
|
||||
this._deleteLazyStoreBalance(signedOrder.makerAssetData, signedOrder.makerAddress);
|
||||
this._deleteLazyStoreProxyAllowance(signedOrder.makerAssetData, signedOrder.makerAddress);
|
||||
this._deleteLazyStoreBalance(signedOrder.takerAssetData, signedOrder.takerAddress);
|
||||
this._deleteLazyStoreProxyAllowance(signedOrder.takerAssetData, signedOrder.takerAddress);
|
||||
|
||||
const zrxAssetData = this._orderFilledCancelledLazyStore.getZRXAssetData();
|
||||
if (!signedOrder.makerFee.isZero()) {
|
||||
this._deleteLazyStoreBalance(zrxAssetData, signedOrder.makerAddress);
|
||||
this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.makerAddress);
|
||||
}
|
||||
if (!signedOrder.takerFee.isZero()) {
|
||||
this._deleteLazyStoreBalance(zrxAssetData, signedOrder.takerAddress);
|
||||
this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.takerAddress);
|
||||
}
|
||||
}
|
||||
private _onOrderExpired(orderHash: string): void {
|
||||
const orderState: OrderState = {
|
||||
isValid: false,
|
||||
orderHash,
|
||||
error: ExchangeContractErrs.OrderFillExpired,
|
||||
};
|
||||
if (this._orderByOrderHash[orderHash] !== undefined) {
|
||||
this.removeOrder(orderHash);
|
||||
if (this._callbackIfExists !== undefined) {
|
||||
this._callbackIfExists(null, orderState);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEntryEvent): Promise<void> {
|
||||
if (err !== null) {
|
||||
if (this._callbackIfExists !== undefined) {
|
||||
this._callbackIfExists(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const maybeDecodedLog = this._collisionResistantAbiDecoder.tryToDecodeLogOrNoop<ContractEventArgs>(
|
||||
// At this moment we are sure that no error occured and log is defined.
|
||||
logIfExists as LogEntryEvent,
|
||||
);
|
||||
const isLogDecoded = ((maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>).event !== undefined;
|
||||
if (!isLogDecoded) {
|
||||
return; // noop
|
||||
}
|
||||
const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>;
|
||||
const transactionHash = decodedLog.transactionHash;
|
||||
switch (decodedLog.event) {
|
||||
case ERC20TokenEvents.Approval:
|
||||
case ERC721TokenEvents.Approval: {
|
||||
// ERC20 and ERC721 Transfer events have the same name so we need to distinguish them by args
|
||||
if (decodedLog.args._value !== undefined) {
|
||||
// ERC20
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ERC20TokenApprovalEventArgs;
|
||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||
this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||
args._owner,
|
||||
tokenAssetData,
|
||||
);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
} else {
|
||||
// ERC721
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ERC721TokenApprovalEventArgs;
|
||||
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
|
||||
this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||
args._owner,
|
||||
tokenAssetData,
|
||||
);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ERC20TokenEvents.Transfer:
|
||||
case ERC721TokenEvents.Transfer: {
|
||||
// ERC20 and ERC721 Transfer events have the same name so we need to distinguish them by args
|
||||
if (decodedLog.args._value !== undefined) {
|
||||
// ERC20
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ERC20TokenTransferEventArgs;
|
||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||
this._deleteLazyStoreBalance(tokenAssetData, args._from);
|
||||
this._deleteLazyStoreBalance(tokenAssetData, args._to);
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||
args._from,
|
||||
tokenAssetData,
|
||||
);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
} else {
|
||||
// ERC721
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ERC721TokenTransferEventArgs;
|
||||
const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
|
||||
this._deleteLazyStoreBalance(tokenAssetData, args._from);
|
||||
this._deleteLazyStoreBalance(tokenAssetData, args._to);
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||
args._from,
|
||||
tokenAssetData,
|
||||
);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ERC721TokenEvents.ApprovalForAll: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ERC721TokenApprovalForAllEventArgs;
|
||||
const tokenAddress = decodedLog.address;
|
||||
this._balanceAndProxyAllowanceLazyStore.deleteAllERC721ProxyAllowance(tokenAddress, args._owner);
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByERC721ByMaker(
|
||||
args._owner,
|
||||
tokenAddress,
|
||||
);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
}
|
||||
case WETH9Events.Deposit: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as WETH9DepositEventArgs;
|
||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||
this._deleteLazyStoreBalance(tokenAssetData, args._owner);
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||
args._owner,
|
||||
tokenAssetData,
|
||||
);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
}
|
||||
case WETH9Events.Withdrawal: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as WETH9WithdrawalEventArgs;
|
||||
const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
|
||||
this._deleteLazyStoreBalance(tokenAssetData, args._owner);
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
|
||||
args._owner,
|
||||
tokenAssetData,
|
||||
);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
}
|
||||
case ExchangeEvents.Fill: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ExchangeFillEventArgs;
|
||||
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
|
||||
// Revalidate orders
|
||||
const orderHash = args.orderHash;
|
||||
const isOrderWatched = this._orderByOrderHash[orderHash] !== undefined;
|
||||
if (isOrderWatched) {
|
||||
await this._emitRevalidateOrdersAsync([orderHash], transactionHash);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExchangeEvents.Cancel: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ExchangeCancelEventArgs;
|
||||
this._orderFilledCancelledLazyStore.deleteIsCancelled(args.orderHash);
|
||||
// Revalidate orders
|
||||
const orderHash = args.orderHash;
|
||||
const isOrderWatched = this._orderByOrderHash[orderHash] !== undefined;
|
||||
if (isOrderWatched) {
|
||||
await this._emitRevalidateOrdersAsync([orderHash], transactionHash);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExchangeEvents.CancelUpTo: {
|
||||
// TODO(logvinov): Do it smarter and actually look at the salt and order epoch
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ExchangeCancelUpToEventArgs;
|
||||
this._orderFilledCancelledLazyStore.deleteAllIsCancelled();
|
||||
// Revalidate orders
|
||||
const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByMaker(args.makerAddress);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw errorUtils.spawnSwitchErr('decodedLog.event', decodedLog.event);
|
||||
}
|
||||
}
|
||||
private async _emitRevalidateOrdersAsync(orderHashes: string[], transactionHash?: string): Promise<void> {
|
||||
for (const orderHash of orderHashes) {
|
||||
const signedOrder = this._orderByOrderHash[orderHash];
|
||||
if (signedOrder === undefined) {
|
||||
continue;
|
||||
}
|
||||
// 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.getOpenOrderStateAsync(signedOrder, transactionHash);
|
||||
if (this._callbackIfExists === undefined) {
|
||||
break; // Unsubscribe was called
|
||||
}
|
||||
if (_.isEqual(orderState, this._orderStateByOrderHashCache[orderHash])) {
|
||||
// Actual order state didn't change
|
||||
continue;
|
||||
} else {
|
||||
this._orderStateByOrderHashCache[orderHash] = orderState;
|
||||
}
|
||||
this._callbackIfExists(null, orderState);
|
||||
}
|
||||
}
|
||||
} // tslint:disable:max-file-line-count
|
@@ -1,30 +0,0 @@
|
||||
import { assert as sharedAssert } from '@0x/assert';
|
||||
// HACK: We need those two unused imports because they're actually used by sharedAssert which gets injected here
|
||||
// tslint:disable:no-unused-variable
|
||||
import { Schema } from '@0x/json-schemas';
|
||||
import { ECSignature } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
// tslint:enable:no-unused-variable
|
||||
import { SupportedProvider } from 'ethereum-types';
|
||||
|
||||
import { signatureUtils } from '@0x/order-utils';
|
||||
|
||||
export const assert = {
|
||||
...sharedAssert,
|
||||
async isValidSignatureAsync(
|
||||
supportedProvider: SupportedProvider,
|
||||
orderHash: string,
|
||||
signature: string,
|
||||
signerAddress: string,
|
||||
exchangeAddress?: string,
|
||||
): Promise<void> {
|
||||
const isValid = await signatureUtils.isValidSignatureAsync(
|
||||
supportedProvider,
|
||||
orderHash,
|
||||
signature,
|
||||
signerAddress,
|
||||
exchangeAddress,
|
||||
);
|
||||
assert.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
|
||||
},
|
||||
};
|
Reference in New Issue
Block a user