aboutsummaryrefslogtreecommitdiffstats
path: root/packages/0x.js/src/contract_wrappers
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-05-10 02:36:28 +0800
committerFabio Berger <me@fabioberger.com>2018-05-10 02:36:28 +0800
commit209266dbed9d7d038c90c2da8d9b99acab77c80c (patch)
treecfefd5ab15bc237716b15687629e0f41362a8e86 /packages/0x.js/src/contract_wrappers
parent69a6166b6a1d39afc24b8dd950ec5d8539a03420 (diff)
downloaddexon-sol-tools-209266dbed9d7d038c90c2da8d9b99acab77c80c.tar.gz
dexon-sol-tools-209266dbed9d7d038c90c2da8d9b99acab77c80c.tar.zst
dexon-sol-tools-209266dbed9d7d038c90c2da8d9b99acab77c80c.zip
Split 0x.js into contract-wrappers, order-watcher but keep 0x.js as a unifying library with the same interface
Diffstat (limited to 'packages/0x.js/src/contract_wrappers')
-rw-r--r--packages/0x.js/src/contract_wrappers/contract_wrapper.ts202
-rw-r--r--packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts204
-rw-r--r--packages/0x.js/src/contract_wrappers/exchange_wrapper.ts964
-rw-r--r--packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts133
-rw-r--r--packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts75
-rw-r--r--packages/0x.js/src/contract_wrappers/token_wrapper.ts434
6 files changed, 0 insertions, 2012 deletions
diff --git a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts b/packages/0x.js/src/contract_wrappers/contract_wrapper.ts
deleted file mode 100644
index 02be2dab3..000000000
--- a/packages/0x.js/src/contract_wrappers/contract_wrapper.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-import { BlockParamLiteral, ContractAbi, FilterObject, LogEntry, LogWithDecodedArgs, RawLog } from '@0xproject/types';
-import { AbiDecoder, intervalUtils } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
-import * as _ from 'lodash';
-import * as Web3 from 'web3';
-
-import {
- Artifact,
- BlockRange,
- ContractEventArgs,
- ContractEvents,
- EventCallback,
- IndexedFilterValues,
- InternalZeroExError,
- ZeroExError,
-} from '../types';
-import { constants } from '../utils/constants';
-import { filterUtils } from '../utils/filter_utils';
-
-const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
- [contractName: string]: ZeroExError;
-} = {
- ZRX: ZeroExError.ZRXContractDoesNotExist,
- EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
- Token: ZeroExError.TokenContractDoesNotExist,
- TokenRegistry: ZeroExError.TokenRegistryContractDoesNotExist,
- TokenTransferProxy: ZeroExError.TokenTransferProxyContractDoesNotExist,
- Exchange: ZeroExError.ExchangeContractDoesNotExist,
-};
-
-export class ContractWrapper {
- protected _web3Wrapper: Web3Wrapper;
- protected _networkId: number;
- private _blockAndLogStreamerIfExists?: BlockAndLogStreamer;
- private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
- private _filters: { [filterToken: string]: FilterObject };
- private _filterCallbacks: {
- [filterToken: string]: EventCallback<ContractEventArgs>;
- };
- private _onLogAddedSubscriptionToken: string | undefined;
- private _onLogRemovedSubscriptionToken: string | undefined;
- constructor(web3Wrapper: Web3Wrapper, networkId: number) {
- this._web3Wrapper = web3Wrapper;
- this._networkId = networkId;
- this._filters = {};
- this._filterCallbacks = {};
- this._blockAndLogStreamerIfExists = undefined;
- this._onLogAddedSubscriptionToken = undefined;
- this._onLogRemovedSubscriptionToken = undefined;
- }
- protected _unsubscribeAll(): void {
- const filterTokens = _.keys(this._filterCallbacks);
- _.each(filterTokens, filterToken => {
- this._unsubscribe(filterToken);
- });
- }
- protected _unsubscribe(filterToken: string, err?: Error): void {
- if (_.isUndefined(this._filters[filterToken])) {
- throw new Error(ZeroExError.SubscriptionNotFound);
- }
- if (!_.isUndefined(err)) {
- const callback = this._filterCallbacks[filterToken];
- callback(err, undefined);
- }
- delete this._filters[filterToken];
- delete this._filterCallbacks[filterToken];
- if (_.isEmpty(this._filters)) {
- this._stopBlockAndLogStream();
- }
- }
- protected _subscribe<ArgsType extends ContractEventArgs>(
- address: string,
- eventName: ContractEvents,
- indexFilterValues: IndexedFilterValues,
- abi: ContractAbi,
- callback: EventCallback<ArgsType>,
- ): string {
- const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
- if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
- this._startBlockAndLogStream();
- }
- const filterToken = filterUtils.generateUUID();
- this._filters[filterToken] = filter;
- this._filterCallbacks[filterToken] = callback as EventCallback<ContractEventArgs>;
- return filterToken;
- }
- protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
- address: string,
- eventName: ContractEvents,
- blockRange: BlockRange,
- indexFilterValues: IndexedFilterValues,
- abi: ContractAbi,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
- const logs = await this._web3Wrapper.getLogsAsync(filter);
- const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
- return logsWithDecodedArguments;
- }
- protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
- log: LogEntry,
- ): LogWithDecodedArgs<ArgsType> | RawLog {
- if (_.isUndefined(this._web3Wrapper.abiDecoder)) {
- throw new Error(InternalZeroExError.NoAbiDecoder);
- }
- const logWithDecodedArgs = this._web3Wrapper.abiDecoder.tryToDecodeLogOrNoop(log);
- return logWithDecodedArgs;
- }
- protected async _getContractAbiAndAddressFromArtifactsAsync(
- artifact: Artifact,
- addressIfExists?: string,
- ): Promise<[ContractAbi, string]> {
- let contractAddress: string;
- if (_.isUndefined(addressIfExists)) {
- if (_.isUndefined(artifact.networks[this._networkId])) {
- throw new Error(ZeroExError.ContractNotDeployedOnNetwork);
- }
- contractAddress = artifact.networks[this._networkId].address.toLowerCase();
- } else {
- contractAddress = addressIfExists;
- }
- const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(contractAddress);
- if (!doesContractExist) {
- throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
- }
- const abiAndAddress: [ContractAbi, string] = [artifact.abi, contractAddress];
- return abiAndAddress;
- }
- protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
- if (_.isUndefined(addressIfExists)) {
- const contractAddress = artifact.networks[this._networkId].address;
- if (_.isUndefined(contractAddress)) {
- throw new Error(ZeroExError.ExchangeContractDoesNotExist);
- }
- return contractAddress;
- } else {
- return addressIfExists;
- }
- }
- private _onLogStateChanged<ArgsType extends ContractEventArgs>(isRemoved: boolean, log: LogEntry): void {
- _.forEach(this._filters, (filter: FilterObject, filterToken: string) => {
- if (filterUtils.matchesFilter(log, filter)) {
- const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs<ArgsType>;
- const logEvent = {
- log: decodedLog,
- isRemoved,
- };
- this._filterCallbacks[filterToken](null, logEvent);
- }
- });
- }
- private _startBlockAndLogStream(): void {
- if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
- throw new Error(ZeroExError.SubscriptionAlreadyPresent);
- }
- this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
- this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
- this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
- );
- const catchAllLogFilter = {};
- this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
- this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval(
- this._reconcileBlockAsync.bind(this),
- constants.DEFAULT_BLOCK_POLLING_INTERVAL,
- this._onReconcileBlockError.bind(this),
- );
- let isRemoved = false;
- this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
- this._onLogStateChanged.bind(this, isRemoved),
- );
- isRemoved = true;
- this._onLogRemovedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogRemoved(
- this._onLogStateChanged.bind(this, isRemoved),
- );
- }
- private _onReconcileBlockError(err: Error): void {
- const filterTokens = _.keys(this._filterCallbacks);
- _.each(filterTokens, filterToken => {
- this._unsubscribe(filterToken, err);
- });
- }
- private _setNetworkId(networkId: number): void {
- this._networkId = networkId;
- }
- private _stopBlockAndLogStream(): void {
- if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
- throw new Error(ZeroExError.SubscriptionNotFound);
- }
- this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string);
- this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string);
- intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamIntervalIfExists as NodeJS.Timer);
- delete this._blockAndLogStreamerIfExists;
- }
- private async _reconcileBlockAsync(): Promise<void> {
- const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest);
- // We need to coerce to Block type cause Web3.Block includes types for mempool blocks
- if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
- // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
- await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
- }
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts
deleted file mode 100644
index fd39de34b..000000000
--- a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts
+++ /dev/null
@@ -1,204 +0,0 @@
-import { schemas } from '@0xproject/json-schemas';
-import { LogWithDecodedArgs } from '@0xproject/types';
-import { AbiDecoder, BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { BlockRange, EventCallback, IndexedFilterValues, TransactionOpts, ZeroExError } from '../types';
-import { assert } from '../utils/assert';
-
-import { ContractWrapper } from './contract_wrapper';
-import { EtherTokenContract, EtherTokenContractEventArgs, EtherTokenEvents } from './generated/ether_token';
-import { TokenWrapper } from './token_wrapper';
-
-/**
- * This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
- * The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
- */
-export class EtherTokenWrapper extends ContractWrapper {
- private _etherTokenContractsByAddress: {
- [address: string]: EtherTokenContract;
- } = {};
- private _tokenWrapper: TokenWrapper;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenWrapper: TokenWrapper) {
- super(web3Wrapper, networkId);
- this._tokenWrapper = tokenWrapper;
- }
- /**
- * Deposit ETH into the Wrapped ETH smart contract and issues the equivalent number of wrapped ETH tokens
- * to the depositor address. These wrapped ETH tokens can be used in 0x trades and are redeemable for 1-to-1
- * for ETH.
- * @param etherTokenAddress EtherToken address you wish to deposit into.
- * @param amountInWei Amount of ETH in Wei the caller wishes to deposit.
- * @param depositor The hex encoded user Ethereum address that would like to make the deposit.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async depositAsync(
- etherTokenAddress: string,
- amountInWei: BigNumber,
- depositor: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
- assert.isValidBaseUnitAmount('amountInWei', amountInWei);
- await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- const normalizedDepositorAddress = depositor.toLowerCase();
-
- const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(normalizedDepositorAddress);
- assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit);
-
- const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
- const txHash = await wethContract.deposit.sendTransactionAsync({
- from: normalizedDepositorAddress,
- value: amountInWei,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Withdraw ETH to the withdrawer's address from the wrapped ETH smart contract in exchange for the
- * equivalent number of wrapped ETH tokens.
- * @param etherTokenAddress EtherToken address you wish to withdraw from.
- * @param amountInWei Amount of ETH in Wei the caller wishes to withdraw.
- * @param withdrawer The hex encoded user Ethereum address that would like to make the withdrawal.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async withdrawAsync(
- etherTokenAddress: string,
- amountInWei: BigNumber,
- withdrawer: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isValidBaseUnitAmount('amountInWei', amountInWei);
- assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
- await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- const normalizedWithdrawerAddress = withdrawer.toLowerCase();
-
- const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(
- normalizedEtherTokenAddress,
- normalizedWithdrawerAddress,
- );
- assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
-
- const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress);
- const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
- from: normalizedWithdrawerAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Gets historical logs without creating a subscription
- * @param etherTokenAddress An address of the ether token that emitted 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);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
- assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const logs = await this._getLogsAsync<ArgsType>(
- normalizedEtherTokenAddress,
- 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);
- const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const subscriptionToken = this._subscribe<ArgsType>(
- normalizedEtherTokenAddress,
- 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();
- }
- /**
- * Retrieves the Ethereum address of the EtherToken contract deployed on the network
- * that the user-passed web3 provider is connected to. If it's not Kovan, Ropsten, Rinkeby, Mainnet or TestRPC
- * (networkId: 50), it will return undefined (e.g a private network).
- * @returns The Ethereum address of the EtherToken contract or undefined.
- */
- public getContractAddressIfExists(): string | undefined {
- const networkSpecificArtifact = artifacts.EtherTokenArtifact.networks[this._networkId];
- const contractAddressIfExists = _.isUndefined(networkSpecificArtifact)
- ? undefined
- : networkSpecificArtifact.address;
- return contractAddressIfExists;
- }
- private _invalidateContractInstance(): void {
- this.unsubscribeAll();
- this._etherTokenContractsByAddress = {};
- }
- private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise<EtherTokenContract> {
- let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress];
- if (!_.isUndefined(etherTokenContract)) {
- return etherTokenContract;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.EtherTokenArtifact,
- etherTokenAddress,
- );
- const contractInstance = new EtherTokenContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- etherTokenContract = contractInstance;
- this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract;
- return etherTokenContract;
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts
deleted file mode 100644
index 6ddaaaf4f..000000000
--- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts
+++ /dev/null
@@ -1,964 +0,0 @@
-import { schemas } from '@0xproject/json-schemas';
-import { getOrderHashHex } from '@0xproject/order-utils';
-import {
- BlockParamLiteral,
- DecodedLogArgs,
- ECSignature,
- LogEntry,
- LogWithDecodedArgs,
- Order,
- SignedOrder,
-} from '@0xproject/types';
-import { AbiDecoder, BigNumber } from '@0xproject/utils';
-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,
- ExchangeContractErrCodes,
- ExchangeContractErrs,
- IndexedFilterValues,
- MethodOpts,
- OrderAddresses,
- OrderCancellationRequest,
- OrderFillRequest,
- OrderState,
- OrderTransactionOpts,
- OrderValues,
- ValidateOrderFillableOpts,
-} from '../types';
-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';
-
-import { ContractWrapper } from './contract_wrapper';
-import {
- ExchangeContract,
- ExchangeContractEventArgs,
- ExchangeEvents,
- LogErrorContractEventArgs,
-} from './generated/exchange';
-import { TokenWrapper } from './token_wrapper';
-const SHOULD_VALIDATE_BY_DEFAULT = true;
-
-interface ExchangeContractErrCodesToMsgs {
- [exchangeContractErrCodes: number]: string;
-}
-
-/**
- * This class includes all the functionality related to calling methods and subscribing to
- * events of the 0x Exchange smart contract.
- */
-export class ExchangeWrapper extends ContractWrapper {
- private _exchangeContractIfExists?: ExchangeContract;
- private _orderValidationUtils: OrderValidationUtils;
- private _tokenWrapper: TokenWrapper;
- private _exchangeContractErrCodesToMsg: ExchangeContractErrCodesToMsgs = {
- [ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
- [ExchangeContractErrCodes.ERROR_CANCEL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
- [ExchangeContractErrCodes.ERROR_FILL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero,
- [ExchangeContractErrCodes.ERROR_CANCEL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero,
- [ExchangeContractErrCodes.ERROR_FILL_TRUNCATION]: ExchangeContractErrs.OrderFillRoundingError,
- [ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.FillBalanceAllowanceError,
- };
- private _contractAddressIfExists?: string;
- private _zrxContractAddressIfExists?: string;
- private static _getOrderAddressesAndValues(order: Order): [OrderAddresses, OrderValues] {
- const orderAddresses: OrderAddresses = [
- order.maker,
- order.taker,
- order.makerTokenAddress,
- order.takerTokenAddress,
- order.feeRecipient,
- ];
- const orderValues: OrderValues = [
- order.makerTokenAmount,
- order.takerTokenAmount,
- order.makerFee,
- order.takerFee,
- order.expirationUnixTimestampSec,
- order.salt,
- ];
- return [orderAddresses, orderValues];
- }
- constructor(
- web3Wrapper: Web3Wrapper,
- networkId: number,
- tokenWrapper: TokenWrapper,
- contractAddressIfExists?: string,
- zrxContractAddressIfExists?: string,
- ) {
- super(web3Wrapper, networkId);
- this._tokenWrapper = tokenWrapper;
- this._orderValidationUtils = new OrderValidationUtils(this);
- this._contractAddressIfExists = contractAddressIfExists;
- this._zrxContractAddressIfExists = zrxContractAddressIfExists;
- }
- /**
- * Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total
- * amount that has been filled or cancelled. The remaining takerAmount can be calculated by
- * subtracting the unavailable amount from the total order takerAmount.
- * @param orderHash The hex encoded orderHash for which you would like to retrieve the
- * unavailable takerAmount.
- * @param methodOpts Optional arguments this method accepts.
- * @return The amount of the order (in taker tokens) that has either been filled or cancelled.
- */
- public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
-
- const exchangeContract = await this._getExchangeContractAsync();
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
- orderHash,
- txData,
- defaultBlock,
- );
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
- return unavailableTakerTokenAmount;
- }
- /**
- * Retrieve the takerAmount of an order that has already been filled.
- * @param orderHash The hex encoded orderHash for which you would like to retrieve the filled takerAmount.
- * @param methodOpts Optional arguments this method accepts.
- * @return The amount of the order (in taker tokens) that has already been filled.
- */
- public async getFilledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
-
- const exchangeContract = await this._getExchangeContractAsync();
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, txData, defaultBlock);
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits);
- return fillAmountInBaseUnits;
- }
- /**
- * Retrieve the takerAmount of an order that has been cancelled.
- * @param orderHash The hex encoded orderHash for which you would like to retrieve the
- * cancelled takerAmount.
- * @param methodOpts Optional arguments this method accepts.
- * @return The amount of the order (in taker tokens) that has been cancelled.
- */
- public async getCancelledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
-
- const exchangeContract = await this._getExchangeContractAsync();
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, txData, defaultBlock);
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits);
- return cancelledAmountInBaseUnits;
- }
- /**
- * Fills a signed order with an amount denominated in baseUnits of the taker token.
- * Since the order in which transactions are included in the next block is indeterminate, race-conditions
- * could arise where a users balance or allowance changes before the fillOrder executes. Because of this,
- * we allow you to specify `shouldThrowOnInsufficientBalanceOrAllowance`.
- * If false, the smart contract will not throw if the parties
- * do not have sufficient balances/allowances, preserving gas costs. Setting it to true forgoes this check
- * and causes the smart contract to throw (using all the gas supplied) instead.
- * @param signedOrder An object that conforms to the SignedOrder interface.
- * @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that
- * you wish to fill.
- * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw
- * if upon execution the tokens cannot be transferred.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider
- * passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async fillOrderAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- shouldThrowOnInsufficientBalanceOrAllowance: boolean,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
-
- const txHash: string = await exchangeInstance.fillOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Sequentially and atomically fills signedOrders up to the specified takerTokenFillAmount.
- * If the fill amount is reached - it succeeds and does not fill the rest of the orders.
- * If fill amount is not reached - it fills as much of the fill amount as possible and succeeds.
- * @param signedOrders The array of signedOrders that you would like to fill until
- * takerTokenFillAmount is reached.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw if
- * upon execution any of the tokens cannot be transferred.
- * If set to false, the call will continue to fill subsequent
- * signedOrders even when some cannot be filled.
- * @param takerAddress The user Ethereum address who would like to fill these
- * orders. Must be available via the supplied Provider
- * passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async fillOrdersUpToAsync(
- signedOrders: SignedOrder[],
- fillTakerTokenAmount: BigNumber,
- shouldThrowOnInsufficientBalanceOrAllowance: boolean,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
- const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
- assert.hasAtMostOneUniqueValue(
- takerTokenAddresses,
- ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed,
- );
- const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- let filledTakerTokenAmount = new BigNumber(0);
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- for (const signedOrder of signedOrders) {
- const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount.minus(filledTakerTokenAmount),
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount);
- if (filledTakerTokenAmount.eq(fillTakerTokenAmount)) {
- break;
- }
- }
- }
-
- if (_.isEmpty(signedOrders)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
-
- const orderAddressesValuesAndSignatureArray = _.map(signedOrders, signedOrder => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(signedOrder),
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- ];
- });
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddressesArray, orderValuesArray, vArray, rArray, sArray] = _.unzip<any>(
- orderAddressesValuesAndSignatureArray,
- );
-
- const exchangeInstance = await this._getExchangeContractAsync();
- const txHash = await exchangeInstance.fillOrdersUpTo.sendTransactionAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Batch version of fillOrderAsync.
- * Executes multiple fills atomically in a single transaction.
- * If shouldThrowOnInsufficientBalanceOrAllowance is set to false, it will continue filling subsequent orders even
- * when earlier ones fail.
- * When shouldThrowOnInsufficientBalanceOrAllowance is set to true, if any fill fails, the entire batch fails.
- * @param orderFillRequests An array of objects that conform to the
- * OrderFillRequest interface.
- * @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw
- * if upon execution any of the tokens cannot be
- * transferred. If set to false, the call will continue to
- * fill subsequent signedOrders even when some
- * cannot be filled.
- * @param takerAddress The user Ethereum address who would like to fill
- * these orders. Must be available via the supplied
- * Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async batchFillOrdersAsync(
- orderFillRequests: OrderFillRequest[],
- shouldThrowOnInsufficientBalanceOrAllowance: boolean,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
- const exchangeContractAddresses = _.map(
- orderFillRequests,
- orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
- );
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- for (const orderFillRequest of orderFillRequests) {
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- orderFillRequest.signedOrder,
- orderFillRequest.takerTokenFillAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- }
- if (_.isEmpty(orderFillRequests)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
-
- const orderAddressesValuesAmountsAndSignatureArray = _.map(orderFillRequests, orderFillRequest => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(orderFillRequest.signedOrder),
- orderFillRequest.takerTokenFillAmount,
- orderFillRequest.signedOrder.ecSignature.v,
- orderFillRequest.signedOrder.ecSignature.r,
- orderFillRequest.signedOrder.ecSignature.s,
- ];
- });
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddressesArray, orderValuesArray, fillTakerTokenAmounts, vArray, rArray, sArray] = _.unzip<any>(
- orderAddressesValuesAmountsAndSignatureArray,
- );
-
- const exchangeInstance = await this._getExchangeContractAsync();
- const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmounts,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled,
- * the fill order is abandoned.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to fill.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async fillOrKillOrderAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
- const txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Batch version of fillOrKill. Allows a taker to specify a batch of orders that will either be atomically
- * filled (each to the specified fillAmount) or aborted.
- * @param orderFillRequests An array of objects that conform to the OrderFillRequest interface.
- * @param takerAddress The user Ethereum address who would like to fill there orders.
- * Must be available via the supplied Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async batchFillOrKillAsync(
- orderFillRequests: OrderFillRequest[],
- takerAddress: string,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
- const exchangeContractAddresses = _.map(
- orderFillRequests,
- orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
- );
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- if (_.isEmpty(orderFillRequests)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- for (const orderFillRequest of orderFillRequests) {
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- orderFillRequest.signedOrder,
- orderFillRequest.takerTokenFillAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- }
-
- const orderAddressesValuesAndTakerTokenFillAmounts = _.map(orderFillRequests, request => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(request.signedOrder),
- request.takerTokenFillAmount,
- request.signedOrder.ecSignature.v,
- request.signedOrder.ecSignature.r,
- request.signedOrder.ecSignature.s,
- ];
- });
-
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip<any>(
- orderAddressesValuesAndTakerTokenFillAmounts,
- );
- const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmounts,
- vParams,
- rParams,
- sParams,
- {
- from: normalizedTakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Cancel a given fill amount of an order. Cancellations are cumulative.
- * @param order An object that conforms to the Order or SignedOrder interface.
- * The order you would like to cancel.
- * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
- * @param transactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async cancelOrderAsync(
- order: Order | SignedOrder,
- cancelTakerTokenAmount: BigNumber,
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema('order', order, schemas.orderSchema);
- assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
- await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
- const normalizedMakerAddress = order.maker.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const orderHash = getOrderHashHex(order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils.validateCancelOrderThrowIfInvalid(
- order,
- cancelTakerTokenAmount,
- unavailableTakerTokenAmount,
- );
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
- const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmount,
- {
- from: normalizedMakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction.
- * All orders must be from the same maker.
- * @param orderCancellationRequests An array of objects that conform to the OrderCancellationRequest
- * interface.
- * @param transactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.asyncZeroExErrorHandler
- public async batchCancelOrdersAsync(
- orderCancellationRequests: OrderCancellationRequest[],
- orderTransactionOpts: OrderTransactionOpts = {},
- ): Promise<string> {
- assert.doesConformToSchema(
- 'orderCancellationRequests',
- orderCancellationRequests,
- schemas.orderCancellationRequestsSchema,
- );
- const exchangeContractAddresses = _.map(
- orderCancellationRequests,
- orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
- );
- assert.hasAtMostOneUniqueValue(
- exchangeContractAddresses,
- ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
- );
- const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
- assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
- const maker = makers[0];
- await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
- const normalizedMakerAddress = maker.toLowerCase();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
- ? SHOULD_VALIDATE_BY_DEFAULT
- : orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- for (const orderCancellationRequest of orderCancellationRequests) {
- const orderHash = getOrderHashHex(orderCancellationRequest.order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils.validateCancelOrderThrowIfInvalid(
- orderCancellationRequest.order,
- orderCancellationRequest.takerTokenCancelAmount,
- unavailableTakerTokenAmount,
- );
- }
- }
- if (_.isEmpty(orderCancellationRequests)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
- const exchangeInstance = await this._getExchangeContractAsync();
- const orderAddressesValuesAndTakerTokenCancelAmounts = _.map(orderCancellationRequests, cancellationRequest => {
- return [
- ...ExchangeWrapper._getOrderAddressesAndValues(cancellationRequest.order),
- cancellationRequest.takerTokenCancelAmount,
- ];
- });
- // We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
- const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip<any>(
- orderAddressesValuesAndTakerTokenCancelAmounts,
- );
- const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmounts,
- {
- from: normalizedMakerAddress,
- gas: orderTransactionOpts.gasLimit,
- gasPrice: orderTransactionOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Subscribe to an event type emitted by the Exchange contract.
- * @param eventName The exchange 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
- * @return Subscription token used later to unsubscribe
- */
- public subscribe<ArgsType extends ExchangeContractEventArgs>(
- eventName: ExchangeEvents,
- indexFilterValues: IndexedFilterValues,
- callback: EventCallback<ArgsType>,
- ): string {
- assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const exchangeContractAddress = this.getContractAddress();
- const subscriptionToken = this._subscribe<ArgsType>(
- exchangeContractAddress,
- eventName,
- indexFilterValues,
- artifacts.ExchangeArtifact.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();
- }
- /**
- * Gets historical logs without creating a subscription
- * @param eventName The exchange 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<ArgsType extends ExchangeContractEventArgs>(
- eventName: ExchangeEvents,
- blockRange: BlockRange,
- indexFilterValues: IndexedFilterValues,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
- assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const exchangeContractAddress = this.getContractAddress();
- const logs = await this._getLogsAsync<ArgsType>(
- exchangeContractAddress,
- eventName,
- blockRange,
- indexFilterValues,
- artifacts.ExchangeArtifact.abi,
- );
- return logs;
- }
- /**
- * Retrieves the Ethereum address of the Exchange contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the Exchange contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ExchangeArtifact, this._contractAddressIfExists);
- return contractAddress;
- }
- /**
- * Checks if order is still fillable and throws an error otherwise. Useful for orderbook
- * pruning where you want to remove stale orders without knowing who the taker will be.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to validate.
- * @param opts An object that conforms to the ValidateOrderFillableOpts
- * interface. Allows specifying a specific fillTakerTokenAmount
- * to validate for.
- */
- public async validateOrderFillableOrThrowAsync(
- signedOrder: SignedOrder,
- opts?: ValidateOrderFillableOpts,
- ): Promise<void> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- const zrxTokenAddress = this.getZRXTokenAddress();
- const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
- exchangeTradeEmulator,
- signedOrder,
- zrxTokenAddress,
- expectedFillTakerTokenAmount,
- );
- }
- /**
- * Checks if order fill will succeed and throws an error otherwise.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to fill.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider passed to 0x.js.
- */
- public async validateFillOrderThrowIfInvalidAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- ): Promise<void> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- /**
- * Checks if cancelling a given order will succeed and throws an informative error if it won't.
- * @param order An object that conforms to the Order or SignedOrder interface.
- * The order you would like to cancel.
- * @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
- */
- public async validateCancelOrderThrowIfInvalidAsync(
- order: Order,
- cancelTakerTokenAmount: BigNumber,
- ): Promise<void> {
- assert.doesConformToSchema('order', order, schemas.orderSchema);
- assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
- const orderHash = getOrderHashHex(order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- OrderValidationUtils.validateCancelOrderThrowIfInvalid(
- order,
- cancelTakerTokenAmount,
- unavailableTakerTokenAmount,
- );
- }
- /**
- * Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
- * @param signedOrder An object that conforms to the SignedOrder interface. The
- * signedOrder you wish to fill.
- * @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
- * @param takerAddress The user Ethereum address who would like to fill this order.
- * Must be available via the supplied Provider passed to 0x.js.
- */
- public async validateFillOrKillOrderThrowIfInvalidAsync(
- signedOrder: SignedOrder,
- fillTakerTokenAmount: BigNumber,
- takerAddress: string,
- ): Promise<void> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
- const normalizedTakerAddress = takerAddress.toLowerCase();
- const zrxTokenAddress = this.getZRXTokenAddress();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator,
- signedOrder,
- fillTakerTokenAmount,
- normalizedTakerAddress,
- zrxTokenAddress,
- );
- }
- /**
- * Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
- * `(fillTakerTokenAmount * makerTokenAmount) / takerTokenAmount`.
- * 0x Protocol does not accept any trades that result in large rounding errors. This means that tokens with few or
- * no decimals can only be filled in quantities and ratios that avoid large rounding errors.
- * @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that you wish to fill.
- * @param takerTokenAmount The order size on the taker side
- * @param makerTokenAmount The order size on the maker side
- */
- public async isRoundingErrorAsync(
- fillTakerTokenAmount: BigNumber,
- takerTokenAmount: BigNumber,
- makerTokenAmount: BigNumber,
- ): Promise<boolean> {
- assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
- assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
- assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
- const exchangeInstance = await this._getExchangeContractAsync();
- const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
- fillTakerTokenAmount,
- takerTokenAmount,
- makerTokenAmount,
- );
- return isRoundingError;
- }
- /**
- * Checks if logs contain LogError, which is emitted by Exchange contract on transaction failure.
- * @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
- */
- public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs> | LogEntry>): void {
- const errLog = _.find(logs, {
- event: ExchangeEvents.LogError,
- });
- if (!_.isUndefined(errLog)) {
- const logArgs = (errLog as LogWithDecodedArgs<LogErrorContractEventArgs>).args;
- const errCode = logArgs.errorId;
- const errMessage = this._exchangeContractErrCodesToMsg[errCode];
- throw new Error(errMessage);
- }
- }
- /**
- * 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
- */
- public getZRXTokenAddress(): string {
- const contractAddress = this._getContractAddress(artifacts.ZRXArtifact, this._zrxContractAddressIfExists);
- return contractAddress;
- }
- private _invalidateContractInstances(): void {
- this.unsubscribeAll();
- delete this._exchangeContractIfExists;
- }
- private async _isValidSignatureUsingContractCallAsync(
- dataHex: string,
- ecSignature: ECSignature,
- signerAddressHex: string,
- ): Promise<boolean> {
- assert.isHexString('dataHex', dataHex);
- assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
- assert.isETHAddressHex('signerAddressHex', signerAddressHex);
- const normalizedSignerAddress = signerAddressHex.toLowerCase();
-
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const isValidSignature = await exchangeInstance.isValidSignature.callAsync(
- normalizedSignerAddress,
- dataHex,
- ecSignature.v,
- ecSignature.r,
- ecSignature.s,
- );
- return isValidSignature;
- }
- private async _getOrderHashHexUsingContractCallAsync(order: Order | SignedOrder): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
- const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
- return orderHashHex;
- }
- private async _getExchangeContractAsync(): Promise<ExchangeContract> {
- if (!_.isUndefined(this._exchangeContractIfExists)) {
- return this._exchangeContractIfExists;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.ExchangeArtifact,
- this._contractAddressIfExists,
- );
- const contractInstance = new ExchangeContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- this._exchangeContractIfExists = contractInstance;
- return this._exchangeContractIfExists;
- }
- private async _getTokenTransferProxyAddressAsync(): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- const tokenTransferProxyAddress = await exchangeInstance.TOKEN_TRANSFER_PROXY_CONTRACT.callAsync();
- const tokenTransferProxyAddressLowerCase = tokenTransferProxyAddress.toLowerCase();
- return tokenTransferProxyAddressLowerCase;
- }
-} // tslint:disable:max-file-line-count
diff --git a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts
deleted file mode 100644
index c4a193264..000000000
--- a/packages/0x.js/src/contract_wrappers/token_registry_wrapper.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { Token, TokenMetadata } from '../types';
-import { assert } from '../utils/assert';
-import { constants } from '../utils/constants';
-
-import { ContractWrapper } from './contract_wrapper';
-import { TokenRegistryContract } from './generated/token_registry';
-
-/**
- * This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
- */
-export class TokenRegistryWrapper extends ContractWrapper {
- private _tokenRegistryContractIfExists?: TokenRegistryContract;
- private _contractAddressIfExists?: string;
- private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined {
- if (metadata[0] === constants.NULL_ADDRESS) {
- return undefined;
- }
- const token = {
- address: metadata[0],
- name: metadata[1],
- symbol: metadata[2],
- decimals: metadata[3],
- };
- return token;
- }
- constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
- super(web3Wrapper, networkId);
- this._contractAddressIfExists = contractAddressIfExists;
- }
- /**
- * Retrieves all the tokens currently listed in the Token Registry smart contract
- * @return An array of objects that conform to the Token interface.
- */
- public async getTokensAsync(): Promise<Token[]> {
- const addresses = await this.getTokenAddressesAsync();
- const tokenPromises: Array<Promise<Token | undefined>> = _.map(addresses, async (address: string) =>
- this.getTokenIfExistsAsync(address),
- );
- const tokens = await Promise.all(tokenPromises);
- return tokens as Token[];
- }
- /**
- * Retrieves all the addresses of the tokens currently listed in the Token Registry smart contract
- * @return An array of token addresses.
- */
- public async getTokenAddressesAsync(): Promise<string[]> {
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const addresses = await tokenRegistryContract.getTokenAddresses.callAsync();
- const lowerCaseAddresses = _.map(addresses, address => address.toLowerCase());
- return lowerCaseAddresses;
- }
- /**
- * Retrieves a token by address currently listed in the Token Registry smart contract
- * @return An object that conforms to the Token interface or undefined if token not found.
- */
- public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> {
- assert.isETHAddressHex('address', address);
- const normalizedAddress = address.toLowerCase();
-
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(normalizedAddress);
- const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
- return token;
- }
- public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string | undefined> {
- assert.isString('symbol', symbol);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol);
- if (addressIfExists === constants.NULL_ADDRESS) {
- return undefined;
- }
- return addressIfExists;
- }
- public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string | undefined> {
- assert.isString('name', name);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name);
- if (addressIfExists === constants.NULL_ADDRESS) {
- return undefined;
- }
- return addressIfExists;
- }
- public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token | undefined> {
- assert.isString('symbol', symbol);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
- const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
- return token;
- }
- public async getTokenByNameIfExistsAsync(name: string): Promise<Token | undefined> {
- assert.isString('name', name);
- const tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
- const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
- return token;
- }
- /**
- * Retrieves the Ethereum address of the TokenRegistry contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the TokenRegistry contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(
- artifacts.TokenRegistryArtifact,
- this._contractAddressIfExists,
- );
- return contractAddress;
- }
- private _invalidateContractInstance(): void {
- delete this._tokenRegistryContractIfExists;
- }
- private async _getTokenRegistryContractAsync(): Promise<TokenRegistryContract> {
- if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
- return this._tokenRegistryContractIfExists;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.TokenRegistryArtifact,
- this._contractAddressIfExists,
- );
- const contractInstance = new TokenRegistryContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- this._tokenRegistryContractIfExists = contractInstance;
- return this._tokenRegistryContractIfExists;
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts
deleted file mode 100644
index be558b5be..000000000
--- a/packages/0x.js/src/contract_wrappers/token_transfer_proxy_wrapper.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { assert } from '../utils/assert';
-
-import { ContractWrapper } from './contract_wrapper';
-import { TokenTransferProxyContract } from './generated/token_transfer_proxy';
-
-/**
- * This class includes the functionality related to interacting with the TokenTransferProxy contract.
- */
-export class TokenTransferProxyWrapper extends ContractWrapper {
- private _tokenTransferProxyContractIfExists?: TokenTransferProxyContract;
- private _contractAddressIfExists?: string;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
- super(web3Wrapper, networkId);
- this._contractAddressIfExists = contractAddressIfExists;
- }
- /**
- * Check if the Exchange contract address is authorized by the TokenTransferProxy contract.
- * @param exchangeContractAddress The hex encoded address of the Exchange contract to call.
- * @return Whether the exchangeContractAddress is authorized.
- */
- public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
- assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress);
- const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase();
- const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
- const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(
- normalizedExchangeContractAddress,
- );
- return isAuthorized;
- }
- /**
- * Get the list of all Exchange contract addresses authorized by the TokenTransferProxy contract.
- * @return The list of authorized addresses.
- */
- public async getAuthorizedAddressesAsync(): Promise<string[]> {
- const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
- const authorizedAddresses = await tokenTransferProxyContractInstance.getAuthorizedAddresses.callAsync();
- return authorizedAddresses;
- }
- /**
- * Retrieves the Ethereum address of the TokenTransferProxy contract deployed on the network
- * that the user-passed web3 provider is connected to.
- * @returns The Ethereum address of the TokenTransferProxy contract being used.
- */
- public getContractAddress(): string {
- const contractAddress = this._getContractAddress(
- artifacts.TokenTransferProxyArtifact,
- this._contractAddressIfExists,
- );
- return contractAddress;
- }
- private _invalidateContractInstance(): void {
- delete this._tokenTransferProxyContractIfExists;
- }
- private async _getTokenTransferProxyContractAsync(): Promise<TokenTransferProxyContract> {
- if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
- return this._tokenTransferProxyContractIfExists;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.TokenTransferProxyArtifact,
- this._contractAddressIfExists,
- );
- const contractInstance = new TokenTransferProxyContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- this._tokenTransferProxyContractIfExists = contractInstance;
- return this._tokenTransferProxyContractIfExists;
- }
-}
diff --git a/packages/0x.js/src/contract_wrappers/token_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_wrapper.ts
deleted file mode 100644
index 194cfb5aa..000000000
--- a/packages/0x.js/src/contract_wrappers/token_wrapper.ts
+++ /dev/null
@@ -1,434 +0,0 @@
-import { schemas } from '@0xproject/json-schemas';
-import { LogWithDecodedArgs } from '@0xproject/types';
-import { AbiDecoder, BigNumber } from '@0xproject/utils';
-import { Web3Wrapper } from '@0xproject/web3-wrapper';
-import * as _ from 'lodash';
-
-import { artifacts } from '../artifacts';
-import { BlockRange, EventCallback, IndexedFilterValues, MethodOpts, TransactionOpts, ZeroExError } from '../types';
-import { assert } from '../utils/assert';
-import { constants } from '../utils/constants';
-
-import { ContractWrapper } from './contract_wrapper';
-import { TokenContract, TokenContractEventArgs, TokenEvents } from './generated/token';
-import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper';
-
-/**
- * This class includes all the functionality related to interacting with ERC20 token contracts.
- * All ERC20 method calls are supported, along with some convenience methods for getting/setting allowances
- * to the 0x Proxy smart contract.
- */
-export class TokenWrapper extends ContractWrapper {
- public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
- private _tokenContractsByAddress: { [address: string]: TokenContract };
- private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
- constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenTransferProxyWrapper: TokenTransferProxyWrapper) {
- super(web3Wrapper, networkId);
- this._tokenContractsByAddress = {};
- this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
- }
- /**
- * Retrieves an owner's ERC20 token balance.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address whose balance you would like to check.
- * @param methodOpts Optional arguments this method accepts.
- * @return The owner's ERC20 token balance in base units.
- */
- public async getBalanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- methodOpts?: MethodOpts,
- ): Promise<BigNumber> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, defaultBlock);
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- balance = new BigNumber(balance);
- return balance;
- }
- /**
- * Sets the spender's allowance to a specified number of baseUnits on behalf of the owner address.
- * Equivalent to the ERC20 spec method `approve`.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance
- * for spenderAddress.
- * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance.
- * @param amountInBaseUnits The allowance amount you would like to set.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- spenderAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('spenderAddress', spenderAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedSpenderAddress = spenderAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
- const txHash = await tokenContract.approve.sendTransactionAsync(normalizedSpenderAddress, amountInBaseUnits, {
- from: normalizedOwnerAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Sets the spender's allowance to an unlimited number of baseUnits on behalf of the owner address.
- * Equivalent to the ERC20 spec method `approve`.
- * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating
- * allowances set to the max amount (e.g ZRX, WETH)
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance
- * for spenderAddress.
- * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setUnlimitedAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- spenderAddress: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isETHAddressHex('spenderAddress', spenderAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- const normalizedSpenderAddress = spenderAddress.toLowerCase();
- const txHash = await this.setAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- normalizedSpenderAddress,
- this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- txOpts,
- );
- return txHash;
- }
- /**
- * Retrieves the owners allowance in baseUnits set to the spender's address.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address whose allowance to spenderAddress
- * you would like to retrieve.
- * @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
- * @param methodOpts Optional arguments this method accepts.
- */
- public async getAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- spenderAddress: string,
- methodOpts?: MethodOpts,
- ): Promise<BigNumber> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isETHAddressHex('spenderAddress', spenderAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- const normalizedSpenderAddress = spenderAddress.toLowerCase();
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- const txData = {};
- let allowanceInBaseUnits = await tokenContract.allowance.callAsync(
- normalizedOwnerAddress,
- normalizedSpenderAddress,
- txData,
- defaultBlock,
- );
- // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
- allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits);
- return allowanceInBaseUnits;
- }
- /**
- * Retrieves the owner's allowance in baseUnits set to the 0x proxy contract.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
- * @param methodOpts Optional arguments this method accepts.
- */
- public async getProxyAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- methodOpts?: MethodOpts,
- ): Promise<BigNumber> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
-
- const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
- const allowanceInBaseUnits = await this.getAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- proxyAddress,
- methodOpts,
- );
- return allowanceInBaseUnits;
- }
- /**
- * Sets the 0x proxy contract's allowance to a specified number of a tokens' baseUnits on behalf
- * of an owner address.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance
- * for the Proxy contract.
- * @param amountInBaseUnits The allowance amount specified in baseUnits.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setProxyAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
- const txHash = await this.setAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- proxyAddress,
- amountInBaseUnits,
- txOpts,
- );
- return txHash;
- }
- /**
- * Sets the 0x proxy contract's allowance to a unlimited number of a tokens' baseUnits on behalf
- * of an owner address.
- * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating
- * allowances set to the max amount (e.g ZRX, WETH)
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance
- * for the Proxy contract.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async setUnlimitedProxyAllowanceAsync(
- tokenAddress: string,
- ownerAddress: string,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedOwnerAddress = ownerAddress.toLowerCase();
- const txHash = await this.setProxyAllowanceAsync(
- normalizedTokenAddress,
- normalizedOwnerAddress,
- this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- txOpts,
- );
- return txHash;
- }
- /**
- * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param fromAddress The hex encoded user Ethereum address that will send the funds.
- * @param toAddress The hex encoded user Ethereum address that will receive the funds.
- * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async transferAsync(
- tokenAddress: string,
- fromAddress: string,
- toAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isETHAddressHex('toAddress', toAddress);
- await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedFromAddress = fromAddress.toLowerCase();
- const normalizedToAddress = toAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
-
- const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
- if (fromAddressBalance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientBalanceForTransfer);
- }
-
- const txHash = await tokenContract.transfer.sendTransactionAsync(normalizedToAddress, amountInBaseUnits, {
- from: normalizedFromAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- });
- return txHash;
- }
- /**
- * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`.
- * Requires the fromAddress to have sufficient funds and to have approved an allowance of
- * `amountInBaseUnits` to `senderAddress`.
- * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
- * @param fromAddress The hex encoded user Ethereum address whose funds are being sent.
- * @param toAddress The hex encoded user Ethereum address that will receive the funds.
- * @param senderAddress The hex encoded user Ethereum address whose initiates the fund transfer. The
- * `fromAddress` must have set an allowance to the `senderAddress`
- * before this call.
- * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer.
- * @param txOpts Transaction parameters.
- * @return Transaction hash.
- */
- public async transferFromAsync(
- tokenAddress: string,
- fromAddress: string,
- toAddress: string,
- senderAddress: string,
- amountInBaseUnits: BigNumber,
- txOpts: TransactionOpts = {},
- ): Promise<string> {
- assert.isETHAddressHex('toAddress', toAddress);
- assert.isETHAddressHex('fromAddress', fromAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper);
- const normalizedToAddress = toAddress.toLowerCase();
- const normalizedFromAddress = fromAddress.toLowerCase();
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- const normalizedSenderAddress = senderAddress.toLowerCase();
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress);
-
- const fromAddressAllowance = await this.getAllowanceAsync(
- normalizedTokenAddress,
- normalizedFromAddress,
- normalizedSenderAddress,
- );
- if (fromAddressAllowance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientAllowanceForTransfer);
- }
-
- const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress);
- if (fromAddressBalance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientBalanceForTransfer);
- }
-
- const txHash = await tokenContract.transferFrom.sendTransactionAsync(
- normalizedFromAddress,
- normalizedToAddress,
- amountInBaseUnits,
- {
- from: normalizedSenderAddress,
- gas: txOpts.gasLimit,
- gasPrice: txOpts.gasPrice,
- },
- );
- return txHash;
- }
- /**
- * Subscribe to an event type emitted by the Token contract.
- * @param tokenAddress The hex encoded address where the ERC20 token is deployed.
- * @param eventName The 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 `{maker: aUserAddressHex}`
- * @param callback Callback that gets called when a log is added/removed
- * @return Subscription token used later to unsubscribe
- */
- public subscribe<ArgsType extends TokenContractEventArgs>(
- tokenAddress: string,
- eventName: TokenEvents,
- indexFilterValues: IndexedFilterValues,
- callback: EventCallback<ArgsType>,
- ): string {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const subscriptionToken = this._subscribe<ArgsType>(
- normalizedTokenAddress,
- eventName,
- indexFilterValues,
- artifacts.TokenArtifact.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();
- }
- /**
- * Gets historical logs without creating a subscription
- * @param tokenAddress An address of the token that emitted the logs.
- * @param eventName The 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 `{_from: aUserAddressHex}`
- * @return Array of logs that match the parameters
- */
- public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
- tokenAddress: string,
- eventName: TokenEvents,
- blockRange: BlockRange,
- indexFilterValues: IndexedFilterValues,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
- assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const logs = await this._getLogsAsync<ArgsType>(
- normalizedTokenAddress,
- eventName,
- blockRange,
- indexFilterValues,
- artifacts.TokenArtifact.abi,
- );
- return logs;
- }
- private _invalidateContractInstances(): void {
- this.unsubscribeAll();
- this._tokenContractsByAddress = {};
- }
- private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
- const normalizedTokenAddress = tokenAddress.toLowerCase();
- let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress];
- if (!_.isUndefined(tokenContract)) {
- return tokenContract;
- }
- const [abi, address] = await this._getContractAbiAndAddressFromArtifactsAsync(
- artifacts.TokenArtifact,
- normalizedTokenAddress,
- );
- const contractInstance = new TokenContract(
- abi,
- address,
- this._web3Wrapper.getProvider(),
- this._web3Wrapper.getContractDefaults(),
- );
- tokenContract = contractInstance;
- this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract;
- return tokenContract;
- }
-}