diff options
Diffstat (limited to 'packages/0x.js/src')
-rw-r--r-- | packages/0x.js/src/0x.ts | 2 | ||||
-rw-r--r-- | packages/0x.js/src/artifacts/EtherToken.json | 38 | ||||
-rw-r--r-- | packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts | 86 | ||||
-rw-r--r-- | packages/0x.js/src/index.ts | 5 | ||||
-rw-r--r-- | packages/0x.js/src/order_watcher/order_state_watcher.ts | 33 | ||||
-rw-r--r-- | packages/0x.js/src/types.ts | 21 |
6 files changed, 173 insertions, 12 deletions
diff --git a/packages/0x.js/src/0x.ts b/packages/0x.js/src/0x.ts index e4965f9a2..7393cc814 100644 --- a/packages/0x.js/src/0x.ts +++ b/packages/0x.js/src/0x.ts @@ -201,7 +201,7 @@ export class ZeroEx { this._web3Wrapper, config.networkId, config.tokenRegistryContractAddress, ); this.etherToken = new EtherTokenWrapper( - this._web3Wrapper, config.networkId, this.token, + this._web3Wrapper, config.networkId, this._abiDecoder, this.token, ); this.orderStateWatcher = new OrderStateWatcher( this._web3Wrapper, this._abiDecoder, this.token, this.exchange, config.orderWatcherConfig, diff --git a/packages/0x.js/src/artifacts/EtherToken.json b/packages/0x.js/src/artifacts/EtherToken.json index de6946cf2..1105af3b0 100644 --- a/packages/0x.js/src/artifacts/EtherToken.json +++ b/packages/0x.js/src/artifacts/EtherToken.json @@ -231,17 +231,51 @@ ], "name": "Approval", "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" } ], "networks": { "1": { - "address": "0x2956356cd2a2bf3202f771f50d3d14a367b48070" + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" }, "3": { "address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a" }, "42": { - "address": "0x05d090b51c40b020eab3bfcb6a2dff130df22e9c" + "address": "0x653e49e301e508a13237c0ddc98ae7d4cd2667a1" }, "50": { "address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c" diff --git a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts index a6acbe45d..969f30463 100644 --- a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts @@ -1,9 +1,20 @@ +import {schemas} from '@0xproject/json-schemas'; import {Web3Wrapper} from '@0xproject/web3-wrapper'; import BigNumber from 'bignumber.js'; import * as _ from 'lodash'; import {artifacts} from '../artifacts'; -import {TransactionOpts, ZeroExError} from '../types'; +import { + BlockRange, + EtherTokenContractEventArgs, + EtherTokenEvents, + EventCallback, + IndexedFilterValues, + LogWithDecodedArgs, + TransactionOpts, + ZeroExError, +} from '../types'; +import {AbiDecoder} from '../utils/abi_decoder'; import {assert} from '../utils/assert'; import {ContractWrapper} from './contract_wrapper'; @@ -15,10 +26,10 @@ import {TokenWrapper} from './token_wrapper'; * The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back. */ export class EtherTokenWrapper extends ContractWrapper { - private _etherTokenContractIfExists?: EtherTokenContract; + private _etherTokenContractsByAddress: {[address: string]: EtherTokenContract} = {}; private _tokenWrapper: TokenWrapper; - constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenWrapper: TokenWrapper) { - super(web3Wrapper, networkId); + constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) { + super(web3Wrapper, networkId, abiDecoder); this._tokenWrapper = tokenWrapper; } /** @@ -75,15 +86,76 @@ export class EtherTokenWrapper extends ContractWrapper { }); return txHash; } + /** + * Gets historical logs without creating a subscription + * @param etherTokenAddress An address of the ether token that emmited the logs. + * @param eventName The ether token 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 `{_owner: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>( + etherTokenAddress: string, eventName: EtherTokenEvents, blockRange: BlockRange, + indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._getLogsAsync<ArgsType>( + etherTokenAddress, eventName, blockRange, indexFilterValues, artifacts.EtherTokenArtifact.abi, + ); + return logs; + } + /** + * Subscribe to an event type emitted by the Token contract. + * @param etherTokenAddress The hex encoded address where the ether token is deployed. + * @param eventName The ether token 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 `{_owner: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @return Subscription token used later to unsubscribe + */ + public subscribe<ArgsType extends EtherTokenContractEventArgs>( + etherTokenAddress: string, eventName: EtherTokenEvents, indexFilterValues: IndexedFilterValues, + callback: EventCallback<ArgsType>): string { + assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); + assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscribe<ArgsType>( + etherTokenAddress, eventName, indexFilterValues, artifacts.EtherTokenArtifact.abi, callback, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + super.unsubscribeAll(); + } private _invalidateContractInstance(): void { - delete this._etherTokenContractIfExists; + this.unsubscribeAll(); + this._etherTokenContractsByAddress = {}; } private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise<EtherTokenContract> { + let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress]; + if (!_.isUndefined(etherTokenContract)) { + return etherTokenContract; + } const web3ContractInstance = await this._instantiateContractIfExistsAsync( artifacts.EtherTokenArtifact, etherTokenAddress, ); const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults()); - this._etherTokenContractIfExists = contractInstance; - return this._etherTokenContractIfExists; + etherTokenContract = contractInstance; + this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract; + return etherTokenContract; } } diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index b75ca4fa3..da06aad34 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -2,6 +2,7 @@ export {ZeroEx} from './0x'; export { Order, + BlockParamLiteral, SignedOrder, ECSignature, ZeroExError, @@ -23,10 +24,14 @@ export { TransferContractEventArgs, ApprovalContractEventArgs, TokenContractEventArgs, + EtherTokenContractEventArgs, + WithdrawalContractEventArgs, + DepositContractEventArgs, ContractEventArgs, ContractEventArg, Web3Provider, ZeroExConfig, + EtherTokenEvents, TransactionReceiptWithDecodedLogs, LogWithDecodedArgs, MethodOpts, 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 c4a9eb1ad..af9814dc8 100644 --- a/packages/0x.js/src/order_watcher/order_state_watcher.ts +++ b/packages/0x.js/src/order_watcher/order_state_watcher.ts @@ -12,6 +12,8 @@ import { ApprovalContractEventArgs, BlockParamLiteral, ContractEventArgs, + DepositContractEventArgs, + EtherTokenEvents, ExchangeContractErrs, ExchangeEvents, LogCancelContractEventArgs, @@ -24,6 +26,7 @@ import { SignedOrder, TokenEvents, TransferContractEventArgs, + WithdrawalContractEventArgs, ZeroExError, } from '../types'; import {AbiDecoder} from '../utils/abi_decoder'; @@ -243,6 +246,36 @@ export class OrderStateWatcher { } break; } + case EtherTokenEvents.Deposit: + { + // Invalidate cache + const args = decodedLog.args as DepositContractEventArgs; + this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner); + // Revalidate orders + makerToken = decodedLog.address; + makerAddress = args._owner; + if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && + !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { + const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); + await this._emitRevalidateOrdersAsync(orderHashes); + } + break; + } + case EtherTokenEvents.Withdrawal: + { + // Invalidate cache + const args = decodedLog.args as WithdrawalContractEventArgs; + this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner); + // Revalidate orders + makerToken = decodedLog.address; + makerAddress = args._owner; + if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) && + !_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) { + const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]); + await this._emitRevalidateOrdersAsync(orderHashes); + } + break; + } case ExchangeEvents.LogFill: { // Invalidate cache diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts index 704e59ce5..e6a2c05d0 100644 --- a/packages/0x.js/src/types.ts +++ b/packages/0x.js/src/types.ts @@ -28,6 +28,7 @@ export enum ZeroExError { export enum InternalZeroExError { NoAbiDecoder = 'NO_ABI_DECODER', ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY', + WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY', } /** @@ -146,8 +147,17 @@ export interface ApprovalContractEventArgs { _spender: string; _value: BigNumber; } +export interface DepositContractEventArgs { + _owner: string; + _value: BigNumber; +} +export interface WithdrawalContractEventArgs { + _owner: string; + _value: BigNumber; +} export type TokenContractEventArgs = TransferContractEventArgs|ApprovalContractEventArgs; -export type ContractEventArgs = ExchangeContractEventArgs|TokenContractEventArgs; +export type EtherTokenContractEventArgs = TokenContractEventArgs|DepositContractEventArgs|WithdrawalContractEventArgs; +export type ContractEventArgs = ExchangeContractEventArgs|TokenContractEventArgs|EtherTokenContractEventArgs; export type ContractEventArg = string|BigNumber; export interface Order { @@ -201,7 +211,14 @@ export enum TokenEvents { Approval = 'Approval', } -export type ContractEvents = TokenEvents|ExchangeEvents; +export enum EtherTokenEvents { + Transfer = 'Transfer', + Approval = 'Approval', + Deposit = 'Deposit', + Withdrawal = 'Withdrawal', +} + +export type ContractEvents = TokenEvents|ExchangeEvents|EtherTokenEvents; export interface IndexedFilterValues { [index: string]: ContractEventArg; |