aboutsummaryrefslogtreecommitdiffstats
path: root/src/contract_wrappers
diff options
context:
space:
mode:
Diffstat (limited to 'src/contract_wrappers')
-rw-r--r--src/contract_wrappers/contract_wrapper.ts152
-rw-r--r--src/contract_wrappers/ether_token_wrapper.ts87
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts866
-rw-r--r--src/contract_wrappers/token_registry_wrapper.ts122
-rw-r--r--src/contract_wrappers/token_transfer_proxy_wrapper.ts60
-rw-r--r--src/contract_wrappers/token_wrapper.ts313
6 files changed, 0 insertions, 1600 deletions
diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts
deleted file mode 100644
index 7997b1647..000000000
--- a/src/contract_wrappers/contract_wrapper.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-import * as _ from 'lodash';
-import * as Web3 from 'web3';
-import {BlockAndLogStreamer, Block} from 'ethereumjs-blockstream';
-import {Web3Wrapper} from '../web3_wrapper';
-import {AbiDecoder} from '../utils/abi_decoder';
-import {
- ZeroExError,
- InternalZeroExError,
- Artifact,
- LogWithDecodedArgs,
- RawLog,
- ContractEvents,
- SubscriptionOpts,
- IndexedFilterValues,
- EventCallback,
- BlockParamLiteral,
- ContractEventArgs,
-} from '../types';
-import {constants} from '../utils/constants';
-import {intervalUtils} from '../utils/interval_utils';
-import {filterUtils} from '../utils/filter_utils';
-
-export class ContractWrapper {
- protected _web3Wrapper: Web3Wrapper;
- private _abiDecoder?: AbiDecoder;
- private _blockAndLogStreamer: BlockAndLogStreamer|undefined;
- private _blockAndLogStreamInterval: NodeJS.Timer;
- private _filters: {[filterToken: string]: Web3.FilterObject};
- private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>};
- private _onLogAddedSubscriptionToken: string|undefined;
- private _onLogRemovedSubscriptionToken: string|undefined;
- constructor(web3Wrapper: Web3Wrapper, abiDecoder?: AbiDecoder) {
- this._web3Wrapper = web3Wrapper;
- this._abiDecoder = abiDecoder;
- this._filters = {};
- this._filterCallbacks = {};
- this._blockAndLogStreamer = undefined;
- this._onLogAddedSubscriptionToken = undefined;
- this._onLogRemovedSubscriptionToken = undefined;
- }
- /**
- * Cancels all existing subscriptions
- */
- public 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: Web3.ContractAbi,
- callback: EventCallback<ArgsType>): string {
- const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
- if (_.isUndefined(this._blockAndLogStreamer)) {
- this._startBlockAndLogStream();
- }
- const filterToken = filterUtils.generateUUID();
- this._filters[filterToken] = filter;
- this._filterCallbacks[filterToken] = callback;
- return filterToken;
- }
- protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
- address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts,
- indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, subscriptionOpts);
- const logs = await this._web3Wrapper.getLogsAsync(filter);
- const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
- return logsWithDecodedArguments;
- }
- protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
- log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
- if (_.isUndefined(this._abiDecoder)) {
- throw new Error(InternalZeroExError.NoAbiDecoder);
- }
- const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
- return logWithDecodedArgs;
- }
- protected async _instantiateContractIfExistsAsync<ContractType extends Web3.ContractInstance>(
- artifact: Artifact, addressIfExists?: string): Promise<ContractType> {
- const contractInstance =
- await this._web3Wrapper.getContractInstanceFromArtifactAsync<ContractType>(artifact, addressIfExists);
- return contractInstance;
- }
- private _onLogStateChanged<ArgsType extends ContractEventArgs>(removed: boolean, log: Web3.LogEntry): void {
- _.forEach(this._filters, (filter: Web3.FilterObject, filterToken: string) => {
- if (filterUtils.matchesFilter(log, filter)) {
- const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs<ArgsType>;
- const logEvent = {
- ...decodedLog,
- removed,
- };
- this._filterCallbacks[filterToken](null, logEvent);
- }
- });
- }
- private _startBlockAndLogStream(): void {
- this._blockAndLogStreamer = new BlockAndLogStreamer(
- this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
- this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
- );
- const catchAllLogFilter = {};
- this._blockAndLogStreamer.addLogFilter(catchAllLogFilter);
- this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
- this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL,
- );
- let removed = false;
- this._onLogAddedSubscriptionToken = this._blockAndLogStreamer.subscribeToOnLogAdded(
- this._onLogStateChanged.bind(this, removed),
- );
- removed = true;
- this._onLogRemovedSubscriptionToken = this._blockAndLogStreamer.subscribeToOnLogRemoved(
- this._onLogStateChanged.bind(this, removed),
- );
- }
- private _stopBlockAndLogStream(): void {
- (this._blockAndLogStreamer as BlockAndLogStreamer).unsubscribeFromOnLogAdded(
- this._onLogAddedSubscriptionToken as string);
- (this._blockAndLogStreamer as BlockAndLogStreamer).unsubscribeFromOnLogRemoved(
- this._onLogRemovedSubscriptionToken as string);
- intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamInterval);
- delete this._blockAndLogStreamer;
- }
- private async _reconcileBlockAsync(): Promise<void> {
- try {
- 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._blockAndLogStreamer)) {
- // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
- this._blockAndLogStreamer.reconcileNewBlock(latestBlock as any as Block);
- }
- } catch (err) {
- const filterTokens = _.keys(this._filterCallbacks);
- _.each(filterTokens, filterToken => {
- this._unsubscribe(filterToken, err);
- });
- }
- }
-}
diff --git a/src/contract_wrappers/ether_token_wrapper.ts b/src/contract_wrappers/ether_token_wrapper.ts
deleted file mode 100644
index 3cd2f0224..000000000
--- a/src/contract_wrappers/ether_token_wrapper.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import * as _ from 'lodash';
-import BigNumber from 'bignumber.js';
-import {Web3Wrapper} from '../web3_wrapper';
-import {ContractWrapper} from './contract_wrapper';
-import {TokenWrapper} from './token_wrapper';
-import {EtherTokenContract, ZeroExError} from '../types';
-import {assert} from '../utils/assert';
-import {artifacts} from '../artifacts';
-
-/**
- * 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 _etherTokenContractIfExists?: EtherTokenContract;
- private _tokenWrapper: TokenWrapper;
- private _contractAddressIfExists?: string;
- constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
- super(web3Wrapper);
- this._tokenWrapper = tokenWrapper;
- this._contractAddressIfExists = contractAddressIfExists;
- }
- /**
- * 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 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.
- * @return Transaction hash.
- */
- public async depositAsync(amountInWei: BigNumber, depositor: string): Promise<string> {
- assert.isValidBaseUnitAmount('amountInWei', amountInWei);
- await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
-
- const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(depositor);
- assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit);
-
- const wethContract = await this._getEtherTokenContractAsync();
- const txHash = await wethContract.deposit.sendTransactionAsync({
- from: depositor,
- value: amountInWei,
- });
- 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 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 withdrawl.
- * @return Transaction hash.
- */
- public async withdrawAsync(amountInWei: BigNumber, withdrawer: string): Promise<string> {
- assert.isValidBaseUnitAmount('amountInWei', amountInWei);
- await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
-
- const wethContractAddress = await this.getContractAddressAsync();
- const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(wethContractAddress, withdrawer);
- assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
-
- const wethContract = await this._getEtherTokenContractAsync();
- const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
- from: withdrawer,
- });
- return txHash;
- }
- /**
- * Retrieves the Wrapped Ether token contract address
- * @return The Wrapped Ether token contract address
- */
- public async getContractAddressAsync(): Promise<string> {
- const wethContract = await this._getEtherTokenContractAsync();
- return wethContract.address;
- }
- private _invalidateContractInstance(): void {
- delete this._etherTokenContractIfExists;
- }
- private async _getEtherTokenContractAsync(): Promise<EtherTokenContract> {
- if (!_.isUndefined(this._etherTokenContractIfExists)) {
- return this._etherTokenContractIfExists;
- }
- const contractInstance = await this._instantiateContractIfExistsAsync<EtherTokenContract>(
- artifacts.EtherTokenArtifact, this._contractAddressIfExists,
- );
- this._etherTokenContractIfExists = contractInstance as EtherTokenContract;
- return this._etherTokenContractIfExists;
- }
-}
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts
deleted file mode 100644
index fe0c5bc00..000000000
--- a/src/contract_wrappers/exchange_wrapper.ts
+++ /dev/null
@@ -1,866 +0,0 @@
-import * as _ from 'lodash';
-import * as Web3 from 'web3';
-import BigNumber from 'bignumber.js';
-import {schemas} from '0x-json-schemas';
-import {Web3Wrapper} from '../web3_wrapper';
-import {
- ECSignature,
- ExchangeContract,
- ExchangeContractErrCodes,
- ExchangeContractErrs,
- ZeroExError,
- OrderValues,
- OrderAddresses,
- Order,
- SignedOrder,
- ExchangeEvents,
- SubscriptionOpts,
- IndexedFilterValues,
- OrderCancellationRequest,
- OrderFillRequest,
- LogErrorContractEventArgs,
- LogFillContractEventArgs,
- LogCancelContractEventArgs,
- LogWithDecodedArgs,
- MethodOpts,
- ValidateOrderFillableOpts,
- OrderTransactionOpts,
- RawLog,
- EventCallback,
- ExchangeContractEventArgs,
- DecodedLogArgs,
-} from '../types';
-import {assert} from '../utils/assert';
-import {utils} from '../utils/utils';
-import {OrderValidationUtils} from '../utils/order_validation_utils';
-import {ContractWrapper} from './contract_wrapper';
-import {TokenWrapper} from './token_wrapper';
-import {decorators} from '../utils/decorators';
-import {AbiDecoder} from '../utils/abi_decoder';
-import {ExchangeTransferSimulator} from '../utils/exchange_transfer_simulator';
-import {artifacts} from '../artifacts';
-
-const SHOULD_VALIDATE_BY_DEFAULT = true;
-
-/**
- * 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 = {
- [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 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, abiDecoder: AbiDecoder,
- tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
- super(web3Wrapper, abiDecoder);
- this._tokenWrapper = tokenWrapper;
- this._orderValidationUtils = new OrderValidationUtils(tokenWrapper, this);
- this._contractAddressIfExists = contractAddressIfExists;
- }
- /**
- * 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 canceled.
- */
- 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;
- let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
- orderHash, 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;
- let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, 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 getCanceledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
-
- const exchangeContract = await this._getExchangeContractAsync();
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, 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 Web3.Provider
- * passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.contractCallErrorHandler
- 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 exchangeInstance = await this._getExchangeContractAsync();
- const shouldValidate = _.isUndefined(orderTransactionOpts) ?
- SHOULD_VALIDATE_BY_DEFAULT :
- orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = await this.getZRXTokenAddressAsync();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
-
- const gas = await exchangeInstance.fillOrder.estimateGasAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: takerAddress,
- },
- );
- const txHash: string = await exchangeInstance.fillOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: takerAddress,
- gas,
- },
- );
- 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 Web3.Provider
- * passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.contractCallErrorHandler
- 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 shouldValidate = _.isUndefined(orderTransactionOpts) ?
- SHOULD_VALIDATE_BY_DEFAULT :
- orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = await this.getZRXTokenAddressAsync();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- for (const signedOrder of signedOrders) {
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
- }
- }
-
- 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 gas = await exchangeInstance.fillOrdersUpTo.estimateGasAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: takerAddress,
- },
- );
- const txHash = await exchangeInstance.fillOrdersUpTo.sendTransactionAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmount,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: takerAddress,
- gas,
- },
- );
- 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
- * Web3.Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.contractCallErrorHandler
- 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 shouldValidate = _.isUndefined(orderTransactionOpts) ?
- SHOULD_VALIDATE_BY_DEFAULT :
- orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = await this.getZRXTokenAddressAsync();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- for (const orderFillRequest of orderFillRequests) {
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
- takerAddress, 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 gas = await exchangeInstance.batchFillOrders.estimateGasAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmounts,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: takerAddress,
- },
- );
- const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync(
- orderAddressesArray,
- orderValuesArray,
- fillTakerTokenAmounts,
- shouldThrowOnInsufficientBalanceOrAllowance,
- vArray,
- rArray,
- sArray,
- {
- from: takerAddress,
- gas,
- },
- );
- 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 Web3.Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.contractCallErrorHandler
- 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 exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts) ?
- SHOULD_VALIDATE_BY_DEFAULT :
- orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = await this.getZRXTokenAddressAsync();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
-
- const gas = await exchangeInstance.fillOrKillOrder.estimateGasAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: takerAddress,
- },
- );
- const txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmount,
- signedOrder.ecSignature.v,
- signedOrder.ecSignature.r,
- signedOrder.ecSignature.s,
- {
- from: takerAddress,
- gas,
- },
- );
- 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 Web3.Provider passed to 0x.js.
- * @param orderTransactionOpts Optional arguments this method accepts.
- * @return Transaction hash.
- */
- @decorators.contractCallErrorHandler
- 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);
- if (_.isEmpty(orderFillRequests)) {
- throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
- }
- const exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts) ?
- SHOULD_VALIDATE_BY_DEFAULT :
- orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const zrxTokenAddress = await this.getZRXTokenAddressAsync();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- for (const orderFillRequest of orderFillRequests) {
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
- takerAddress, 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 gas = await exchangeInstance.batchFillOrKillOrders.estimateGasAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmounts,
- vParams,
- rParams,
- sParams,
- {
- from: takerAddress,
- },
- );
- const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
- orderAddresses,
- orderValues,
- fillTakerTokenAmounts,
- vParams,
- rParams,
- sParams,
- {
- from: takerAddress,
- gas,
- },
- );
- 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.contractCallErrorHandler
- 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 exchangeInstance = await this._getExchangeContractAsync();
-
- const shouldValidate = _.isUndefined(orderTransactionOpts) ?
- SHOULD_VALIDATE_BY_DEFAULT :
- orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- const orderHash = utils.getOrderHashHex(order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- await this._orderValidationUtils.validateCancelOrderThrowIfInvalidAsync(
- order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
- }
-
- const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
- const gas = await exchangeInstance.cancelOrder.estimateGasAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmount,
- {
- from: order.maker,
- },
- );
- const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmount,
- {
- from: order.maker,
- gas,
- },
- );
- 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.contractCallErrorHandler
- 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 shouldValidate = _.isUndefined(orderTransactionOpts) ?
- SHOULD_VALIDATE_BY_DEFAULT :
- orderTransactionOpts.shouldValidate;
- if (shouldValidate) {
- for (const orderCancellationRequest of orderCancellationRequests) {
- const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- await this._orderValidationUtils.validateCancelOrderThrowIfInvalidAsync(
- 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 gas = await exchangeInstance.batchCancelOrders.estimateGasAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmounts,
- {
- from: maker,
- },
- );
- const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
- orderAddresses,
- orderValues,
- cancelTakerTokenAmounts,
- {
- from: maker,
- gas,
- },
- );
- 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 async subscribeAsync<ArgsType extends ExchangeContractEventArgs>(
- eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
- callback: EventCallback<ArgsType>): Promise<string> {
- assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const exchangeContractAddress = await this.getContractAddressAsync();
- 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);
- }
- /**
- * Gets historical logs without creating a subscription
- * @param eventName The exchange contract event you would like to subscribe to.
- * @param subscriptionOpts Subscriptions options that let you configure the subscription.
- * @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, subscriptionOpts: SubscriptionOpts, indexFilterValues: IndexedFilterValues,
- ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
- assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const exchangeContractAddress = await this.getContractAddressAsync();
- const logs = await this._getLogsAsync<ArgsType>(
- exchangeContractAddress, eventName, subscriptionOpts, 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 async getContractAddressAsync(): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- const exchangeAddress = exchangeInstance.address;
- return exchangeAddress;
- }
- /**
- * 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 = await this.getZRXTokenAddressAsync();
- const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- 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 Web3.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 zrxTokenAddress = await this.getZRXTokenAddressAsync();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, 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 = utils.getOrderHashHex(order);
- const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
- await this._orderValidationUtils.validateCancelOrderThrowIfInvalidAsync(
- 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 Web3.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 zrxTokenAddress = await this.getZRXTokenAddressAsync();
- const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
- await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
- exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, 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 emmited by Exchange contract on transaction failure.
- * @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
- */
- public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>): void {
- const errLog = _.find(logs, {
- event: ExchangeEvents.LogError,
- }) as LogWithDecodedArgs<LogErrorContractEventArgs>|undefined;
- if (!_.isUndefined(errLog)) {
- const logArgs = errLog.args;
- const errCode = logArgs.errorId.toNumber();
- const errMessage = this._exchangeContractErrCodesToMsg[errCode];
- throw new Error(errMessage);
- }
- }
- /**
- * Returns the ZRX token address used by the exchange contract.
- * @return Address of ZRX token
- */
- public async getZRXTokenAddressAsync(): Promise<string> {
- const exchangeInstance = await this._getExchangeContractAsync();
- const ZRXtokenAddress = await exchangeInstance.ZRX_TOKEN_CONTRACT.callAsync();
- return ZRXtokenAddress;
- }
- private async _invalidateContractInstancesAsync(): Promise<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 exchangeInstance = await this._getExchangeContractAsync();
-
- const isValidSignature = await exchangeInstance.isValidSignature.callAsync(
- signerAddressHex,
- 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 contractInstance = await this._instantiateContractIfExistsAsync<ExchangeContract>(
- artifacts.ExchangeArtifact, this._contractAddressIfExists,
- );
- this._exchangeContractIfExists = contractInstance as ExchangeContract;
- 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;
- }
-}
diff --git a/src/contract_wrappers/token_registry_wrapper.ts b/src/contract_wrappers/token_registry_wrapper.ts
deleted file mode 100644
index 2cc5a9aa0..000000000
--- a/src/contract_wrappers/token_registry_wrapper.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import * as _ from 'lodash';
-import {Web3Wrapper} from '../web3_wrapper';
-import {assert} from '../utils/assert';
-import {Token, TokenRegistryContract, TokenMetadata} from '../types';
-import {constants} from '../utils/constants';
-import {ContractWrapper} from './contract_wrapper';
-import {artifacts} from '../artifacts';
-
-/**
- * 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;
- constructor(web3Wrapper: Web3Wrapper, contractAddressIfExists?: string) {
- super(web3Wrapper);
- 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 tokenRegistryContract = await this._getTokenRegistryContractAsync();
-
- const addresses = await this.getTokenAddressesAsync();
- const tokenPromises: Array<Promise<Token|undefined>> = _.map(
- addresses,
- (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();
- return addresses;
- }
- /**
- * 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 tokenRegistryContract = await this._getTokenRegistryContractAsync();
- const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address);
- const token = this._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 = this._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 = this._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 async getContractAddressAsync(): Promise<string> {
- const tokenRegistryInstance = await this._getTokenRegistryContractAsync();
- const tokenRegistryAddress = tokenRegistryInstance.address;
- return tokenRegistryAddress;
- }
- private _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].toNumber(),
- };
- return token;
- }
- private _invalidateContractInstance(): void {
- delete this._tokenRegistryContractIfExists;
- }
- private async _getTokenRegistryContractAsync(): Promise<TokenRegistryContract> {
- if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
- return this._tokenRegistryContractIfExists;
- }
- const contractInstance = await this._instantiateContractIfExistsAsync<TokenRegistryContract>(
- artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
- );
- this._tokenRegistryContractIfExists = contractInstance as TokenRegistryContract;
- return this._tokenRegistryContractIfExists;
- }
-}
diff --git a/src/contract_wrappers/token_transfer_proxy_wrapper.ts b/src/contract_wrappers/token_transfer_proxy_wrapper.ts
deleted file mode 100644
index f81845af9..000000000
--- a/src/contract_wrappers/token_transfer_proxy_wrapper.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import * as _ from 'lodash';
-import {Web3Wrapper} from '../web3_wrapper';
-import {ContractWrapper} from './contract_wrapper';
-import {artifacts} from '../artifacts';
-import {TokenTransferProxyContract} from '../types';
-
-/**
- * This class includes the functionality related to interacting with the TokenTransferProxy contract.
- */
-export class TokenTransferProxyWrapper extends ContractWrapper {
- private _tokenTransferProxyContractIfExists?: TokenTransferProxyContract;
- private _tokenTransferProxyContractAddressFetcher: () => Promise<string>;
- constructor(web3Wrapper: Web3Wrapper, tokenTransferProxyContractAddressFetcher: () => Promise<string>) {
- super(web3Wrapper);
- this._tokenTransferProxyContractAddressFetcher = tokenTransferProxyContractAddressFetcher;
- }
- /**
- * 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> {
- const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
- const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(exchangeContractAddress);
- 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 async getContractAddressAsync(): Promise<string> {
- const proxyInstance = await this._getTokenTransferProxyContractAsync();
- const proxyAddress = proxyInstance.address;
- return proxyAddress;
- }
- private _invalidateContractInstance(): void {
- delete this._tokenTransferProxyContractIfExists;
- }
- private async _getTokenTransferProxyContractAsync(): Promise<TokenTransferProxyContract> {
- if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
- return this._tokenTransferProxyContractIfExists;
- }
- const contractAddress = await this._tokenTransferProxyContractAddressFetcher();
- const contractInstance = await this._instantiateContractIfExistsAsync<TokenTransferProxyContract>(
- artifacts.TokenTransferProxyArtifact, contractAddress,
- );
- this._tokenTransferProxyContractIfExists = contractInstance as TokenTransferProxyContract;
- return this._tokenTransferProxyContractIfExists;
- }
-}
diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts
deleted file mode 100644
index 614ac19d4..000000000
--- a/src/contract_wrappers/token_wrapper.ts
+++ /dev/null
@@ -1,313 +0,0 @@
-import * as _ from 'lodash';
-import BigNumber from 'bignumber.js';
-import {schemas} from '0x-json-schemas';
-import {Web3Wrapper} from '../web3_wrapper';
-import {assert} from '../utils/assert';
-import {constants} from '../utils/constants';
-import {ContractWrapper} from './contract_wrapper';
-import {AbiDecoder} from '../utils/abi_decoder';
-import {artifacts} from '../artifacts';
-import {
- TokenContract,
- ZeroExError,
- TokenEvents,
- IndexedFilterValues,
- SubscriptionOpts,
- MethodOpts,
- LogWithDecodedArgs,
- EventCallback,
- TokenContractEventArgs,
-} from '../types';
-
-const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 47275;
-
-/**
- * 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 _tokenTransferProxyContractAddressFetcher: () => Promise<string>;
- constructor(web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder,
- tokenTransferProxyContractAddressFetcher: () => Promise<string>) {
- super(web3Wrapper, abiDecoder);
- this._tokenContractsByAddress = {};
- this._tokenTransferProxyContractAddressFetcher = tokenTransferProxyContractAddressFetcher;
- }
- /**
- * 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 tokenContract = await this._getTokenContractAsync(tokenAddress);
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- let balance = await tokenContract.balanceOf.callAsync(ownerAddress, 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.
- * @return Transaction hash.
- */
- public async setAllowanceAsync(tokenAddress: string, ownerAddress: string, spenderAddress: string,
- amountInBaseUnits: BigNumber): Promise<string> {
- await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
- assert.isETHAddressHex('spenderAddress', spenderAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(tokenAddress);
- // Hack: for some reason default estimated gas amount causes `base fee exceeds gas limit` exception
- // on testrpc. Probably related to https://github.com/ethereumjs/testrpc/issues/294
- // TODO: Debug issue in testrpc and submit a PR, then remove this hack
- const networkIdIfExists = await this._web3Wrapper.getNetworkIdIfExistsAsync();
- const gas = networkIdIfExists === constants.TESTRPC_NETWORK_ID ? ALLOWANCE_TO_ZERO_GAS_AMOUNT : undefined;
- const txHash = await tokenContract.approve.sendTransactionAsync(spenderAddress, amountInBaseUnits, {
- from: ownerAddress,
- gas,
- });
- 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.
- * @return Transaction hash.
- */
- public async setUnlimitedAllowanceAsync(tokenAddress: string, ownerAddress: string,
- spenderAddress: string): Promise<string> {
- const txHash = await this.setAllowanceAsync(
- tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- 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);
-
- const tokenContract = await this._getTokenContractAsync(tokenAddress);
- const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
- let allowanceInBaseUnits = await tokenContract.allowance.callAsync(ownerAddress, spenderAddress, 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 proxyAddress = await this._getTokenTransferProxyAddressAsync();
- const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, 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.
- * @return Transaction hash.
- */
- public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
- amountInBaseUnits: BigNumber): Promise<string> {
- assert.isETHAddressHex('ownerAddress', ownerAddress);
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const proxyAddress = await this._getTokenTransferProxyAddressAsync();
- const txHash = await this.setAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits);
- 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.
- * @return Transaction hash.
- */
- public async setUnlimitedProxyAllowanceAsync(tokenAddress: string, ownerAddress: string): Promise<string> {
- const txHash = await this.setProxyAllowanceAsync(
- tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
- );
- 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.
- * @return Transaction hash.
- */
- public async transferAsync(tokenAddress: string, fromAddress: string, toAddress: string,
- amountInBaseUnits: BigNumber): Promise<string> {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
- assert.isETHAddressHex('toAddress', toAddress);
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(tokenAddress);
-
- const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress);
- if (fromAddressBalance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientBalanceForTransfer);
- }
-
- const txHash = await tokenContract.transfer.sendTransactionAsync(toAddress, amountInBaseUnits, {
- from: fromAddress,
- });
- 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.
- * @return Transaction hash.
- */
- public async transferFromAsync(tokenAddress: string, fromAddress: string, toAddress: string,
- senderAddress: string, amountInBaseUnits: BigNumber):
- Promise<string> {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.isETHAddressHex('fromAddress', fromAddress);
- assert.isETHAddressHex('toAddress', toAddress);
- await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper);
- assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
-
- const tokenContract = await this._getTokenContractAsync(tokenAddress);
-
- const fromAddressAllowance = await this.getAllowanceAsync(tokenAddress, fromAddress, senderAddress);
- if (fromAddressAllowance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientAllowanceForTransfer);
- }
-
- const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress);
- if (fromAddressBalance.lessThan(amountInBaseUnits)) {
- throw new Error(ZeroExError.InsufficientBalanceForTransfer);
- }
-
- const txHash = await tokenContract.transferFrom.sendTransactionAsync(
- fromAddress, toAddress, amountInBaseUnits,
- {
- from: senderAddress,
- },
- );
- 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);
- assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- assert.isFunction('callback', callback);
- const subscriptionToken = this._subscribe<ArgsType>(
- tokenAddress, 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);
- }
- /**
- * Gets historical logs without creating a subscription
- * @param tokenAddress An address of the token that emmited the logs.
- * @param eventName The token contract event you would like to subscribe to.
- * @param subscriptionOpts Subscriptions options that let you configure the subscription.
- * @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, subscriptionOpts: SubscriptionOpts,
- indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
- assert.isETHAddressHex('tokenAddress', tokenAddress);
- assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
- assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema);
- assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const logs = await this._getLogsAsync<ArgsType>(
- tokenAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.TokenArtifact.abi,
- );
- return logs;
- }
- private _invalidateContractInstancesAsync(): void {
- this.unsubscribeAll();
- this._tokenContractsByAddress = {};
- }
- private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
- let tokenContract = this._tokenContractsByAddress[tokenAddress];
- if (!_.isUndefined(tokenContract)) {
- return tokenContract;
- }
- const contractInstance = await this._instantiateContractIfExistsAsync<TokenContract>(
- artifacts.TokenArtifact, tokenAddress,
- );
- tokenContract = contractInstance as TokenContract;
- this._tokenContractsByAddress[tokenAddress] = tokenContract;
- return tokenContract;
- }
- private async _getTokenTransferProxyAddressAsync(): Promise<string> {
- const tokenTransferProxyContractAddress = await this._tokenTransferProxyContractAddressFetcher();
- return tokenTransferProxyContractAddress;
- }
-}