From 7a21c6854bec32f9a36e8ca3de14a815e9c9fa7d Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 23 Nov 2017 11:14:21 -0600 Subject: Add option config for gasPrice and gasLimit for every transaction sending method --- packages/0x.js/src/contract.ts | 22 +++- .../src/contract_wrappers/ether_token_wrapper.ts | 14 ++- .../src/contract_wrappers/exchange_wrapper.ts | 139 +++++---------------- .../0x.js/src/contract_wrappers/token_wrapper.ts | 41 +++--- packages/0x.js/src/types.ts | 17 ++- 5 files changed, 95 insertions(+), 138 deletions(-) diff --git a/packages/0x.js/src/contract.ts b/packages/0x.js/src/contract.ts index e9c49c9f1..347f47aa0 100644 --- a/packages/0x.js/src/contract.ts +++ b/packages/0x.js/src/contract.ts @@ -34,9 +34,10 @@ export class Contract implements Web3.ContractInstance { } else { const cbStyleFunction = this.contract[functionAbi.name]; const cbStyleEstimateGasFunction = this.contract[functionAbi.name].estimateGas; + const estimateGasAsync = promisify(cbStyleEstimateGasFunction, this.contract); this[functionAbi.name] = { - estimateGasAsync: promisify(cbStyleEstimateGasFunction, this.contract), - sendTransactionAsync: this.promisifyWithDefaultParams(cbStyleFunction), + estimateGasAsync, + sendTransactionAsync: this.promisifyWithDefaultParams(cbStyleFunction, estimateGasAsync), }; } }); @@ -47,18 +48,29 @@ export class Contract implements Web3.ContractInstance { this[eventAbi.name] = this.contract[eventAbi.name]; }); } - private promisifyWithDefaultParams(fn: (...args: any[]) => void): (...args: any[]) => Promise { + private promisifyWithDefaultParams( + web3CbStyleFunction: (...args: any[]) => void, + estimateGasAsync: (...args: any[]) => Promise, + ): (...args: any[]) => Promise { const promisifiedWithDefaultParams = async (...args: any[]) => { - const promise = new Promise((resolve, reject) => { + const promise = new Promise(async (resolve, reject) => { const lastArg = args[args.length - 1]; let txData: Partial = {}; if (this.isTxData(lastArg)) { txData = args.pop(); } + // Gas amounts priorities: + // 1 - method level + // 2 - Library defaults + // 3 - estimate txData = { ...this.defaults, ...txData, }; + if (_.isUndefined(txData.gas)) { + const estimatedGas = await estimateGasAsync.apply(this.contract, [...args, txData]); + txData.gas = estimatedGas; + } const callback = (err: Error, data: any) => { if (_.isNull(err)) { resolve(data); @@ -68,7 +80,7 @@ export class Contract implements Web3.ContractInstance { }; args.push(txData); args.push(callback); - fn.apply(this.contract, args); + web3CbStyleFunction.apply(this.contract, args); }); return promise; }; diff --git a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts index 7a3f2bc52..65f1cda24 100644 --- a/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts @@ -2,7 +2,7 @@ import BigNumber from 'bignumber.js'; import * as _ from 'lodash'; import {artifacts} from '../artifacts'; -import {EtherTokenContract, ZeroExError} from '../types'; +import {EtherTokenContract, TransactionOpts, ZeroExError} from '../types'; import {assert} from '../utils/assert'; import {Web3Wrapper} from '../web3_wrapper'; @@ -27,10 +27,11 @@ export class EtherTokenWrapper extends ContractWrapper { * 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. + * @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(amountInWei: BigNumber, depositor: string): Promise { + public async depositAsync(amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts): Promise { assert.isValidBaseUnitAmount('amountInWei', amountInWei); await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); @@ -41,6 +42,8 @@ export class EtherTokenWrapper extends ContractWrapper { const txHash = await wethContract.deposit.sendTransactionAsync({ from: depositor, value: amountInWei, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, }); return txHash; } @@ -49,9 +52,10 @@ export class EtherTokenWrapper extends ContractWrapper { * 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. + * @param txOpts Transaction parameters. * @return Transaction hash. */ - public async withdrawAsync(amountInWei: BigNumber, withdrawer: string): Promise { + public async withdrawAsync(amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts): Promise { assert.isValidBaseUnitAmount('amountInWei', amountInWei); await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); @@ -62,6 +66,8 @@ export class EtherTokenWrapper extends ContractWrapper { const wethContract = await this._getEtherTokenContractAsync(); const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, { from: withdrawer, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, }); return txHash; } diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts index 91b41c4a4..76a537b45 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -169,16 +169,14 @@ export class ExchangeWrapper extends ContractWrapper { public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, shouldThrowOnInsufficientBalanceOrAllowance: boolean, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise { + orderTransactionOpts: OrderTransactionOpts = {}): Promise { 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; + const shouldValidate = orderTransactionOpts.shouldValidate || SHOULD_VALIDATE_BY_DEFAULT; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -188,18 +186,6 @@ export class ExchangeWrapper extends ContractWrapper { 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, @@ -210,7 +196,8 @@ export class ExchangeWrapper extends ContractWrapper { signedOrder.ecSignature.s, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -236,7 +223,7 @@ export class ExchangeWrapper extends ContractWrapper { public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber, shouldThrowOnInsufficientBalanceOrAllowance: boolean, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise { + orderTransactionOpts: OrderTransactionOpts = {}): Promise { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress); assert.hasAtMostOneUniqueValue(takerTokenAddresses, @@ -248,9 +235,7 @@ export class ExchangeWrapper extends ContractWrapper { assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const shouldValidate = _.isUndefined(orderTransactionOpts) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = orderTransactionOpts.shouldValidate || SHOULD_VALIDATE_BY_DEFAULT; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -278,18 +263,6 @@ export class ExchangeWrapper extends ContractWrapper { ); 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, @@ -300,7 +273,8 @@ export class ExchangeWrapper extends ContractWrapper { sArray, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -328,7 +302,7 @@ export class ExchangeWrapper extends ContractWrapper { public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[], shouldThrowOnInsufficientBalanceOrAllowance: boolean, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise { + orderTransactionOpts: OrderTransactionOpts = {}): Promise { assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); const exchangeContractAddresses = _.map( orderFillRequests, @@ -338,9 +312,7 @@ export class ExchangeWrapper extends ContractWrapper { ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress); assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const shouldValidate = _.isUndefined(orderTransactionOpts) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = orderTransactionOpts.shouldValidate || SHOULD_VALIDATE_BY_DEFAULT; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -370,18 +342,6 @@ export class ExchangeWrapper extends ContractWrapper { ); 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, @@ -392,7 +352,8 @@ export class ExchangeWrapper extends ContractWrapper { sArray, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -411,16 +372,14 @@ export class ExchangeWrapper extends ContractWrapper { @decorators.contractCallErrorHandler public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise { + orderTransactionOpts: OrderTransactionOpts = {}): Promise { 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; + const shouldValidate = orderTransactionOpts.shouldValidate || SHOULD_VALIDATE_BY_DEFAULT; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -429,18 +388,6 @@ export class ExchangeWrapper extends ContractWrapper { } 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, @@ -450,7 +397,8 @@ export class ExchangeWrapper extends ContractWrapper { signedOrder.ecSignature.s, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -467,7 +415,7 @@ export class ExchangeWrapper extends ContractWrapper { @decorators.contractCallErrorHandler public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[], takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise { + orderTransactionOpts: OrderTransactionOpts = {}): Promise { assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); const exchangeContractAddresses = _.map( @@ -482,9 +430,7 @@ export class ExchangeWrapper extends ContractWrapper { } const exchangeInstance = await this._getExchangeContractAsync(); - const shouldValidate = _.isUndefined(orderTransactionOpts) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = orderTransactionOpts.shouldValidate || SHOULD_VALIDATE_BY_DEFAULT; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -509,18 +455,6 @@ export class ExchangeWrapper extends ContractWrapper { // We use _.unzip because _.unzip doesn't type check if values have different types :'( const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip(orderAddressesValuesAndTakerTokenFillAmounts); - - const gas = await exchangeInstance.batchFillOrKillOrders.estimateGasAsync( - orderAddresses, - orderValues, - fillTakerTokenAmounts, - vParams, - rParams, - sParams, - { - from: takerAddress, - }, - ); const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync( orderAddresses, orderValues, @@ -530,7 +464,8 @@ export class ExchangeWrapper extends ContractWrapper { sParams, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -546,16 +481,14 @@ export class ExchangeWrapper extends ContractWrapper { @decorators.contractCallErrorHandler public async cancelOrderAsync(order: Order|SignedOrder, cancelTakerTokenAmount: BigNumber, - orderTransactionOpts?: OrderTransactionOpts): Promise { + orderTransactionOpts: OrderTransactionOpts = {}): Promise { 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; + const shouldValidate = orderTransactionOpts.shouldValidate || SHOULD_VALIDATE_BY_DEFAULT; if (shouldValidate) { const orderHash = utils.getOrderHashHex(order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); @@ -564,21 +497,14 @@ export class ExchangeWrapper extends ContractWrapper { } 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, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -593,7 +519,7 @@ export class ExchangeWrapper extends ContractWrapper { */ @decorators.contractCallErrorHandler public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[], - orderTransactionOpts?: OrderTransactionOpts): Promise { + orderTransactionOpts: OrderTransactionOpts = {}): Promise { assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests, schemas.orderCancellationRequestsSchema); const exchangeContractAddresses = _.map( @@ -606,9 +532,7 @@ export class ExchangeWrapper extends ContractWrapper { 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; + const shouldValidate = orderTransactionOpts.shouldValidate || SHOULD_VALIDATE_BY_DEFAULT; if (shouldValidate) { for (const orderCancellationRequest of orderCancellationRequests) { const orderHash = utils.getOrderHashHex(orderCancellationRequest.order); @@ -633,21 +557,14 @@ export class ExchangeWrapper extends ContractWrapper { // We use _.unzip because _.unzip doesn't type check if values have different types :'( const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip(orderAddressesValuesAndTakerTokenCancelAmounts); - const gas = await exchangeInstance.batchCancelOrders.estimateGasAsync( - orderAddresses, - orderValues, - cancelTakerTokenAmounts, - { - from: maker, - }, - ); const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync( orderAddresses, orderValues, cancelTakerTokenAmounts, { from: maker, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; diff --git a/packages/0x.js/src/contract_wrappers/token_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_wrapper.ts index 5c6cfeaed..4a1dfcf8d 100644 --- a/packages/0x.js/src/contract_wrappers/token_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/token_wrapper.ts @@ -12,6 +12,7 @@ import { TokenContract, TokenContractEventArgs, TokenEvents, + TransactionOpts, ZeroExError, } from '../types'; import {AbiDecoder} from '../utils/abi_decoder'; @@ -66,24 +67,21 @@ export class TokenWrapper extends ContractWrapper { * 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): Promise { + amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise { 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 networkId = this._web3Wrapper.getNetworkId(); - const gas = networkId === constants.TESTRPC_NETWORK_ID ? ALLOWANCE_TO_ZERO_GAS_AMOUNT : undefined; const txHash = await tokenContract.approve.sendTransactionAsync(spenderAddress, amountInBaseUnits, { from: ownerAddress, - gas, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, }); return txHash; } @@ -96,12 +94,13 @@ export class TokenWrapper extends ContractWrapper { * @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): Promise { + spenderAddress: string, txOpts: TransactionOpts = {}): Promise { const txHash = await this.setAllowanceAsync( - tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, ); return txHash; } @@ -147,16 +146,19 @@ export class TokenWrapper extends ContractWrapper { * @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): Promise { + amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise { assert.isETHAddressHex('ownerAddress', ownerAddress); assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress(); - const txHash = await this.setAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits); + const txHash = await this.setAllowanceAsync( + tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts, + ); return txHash; } /** @@ -167,11 +169,14 @@ export class TokenWrapper extends ContractWrapper { * @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): Promise { + public async setUnlimitedProxyAllowanceAsync( + tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {}, + ): Promise { const txHash = await this.setProxyAllowanceAsync( - tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, + tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts, ); return txHash; } @@ -181,10 +186,11 @@ export class TokenWrapper extends ContractWrapper { * @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): Promise { + amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise { assert.isETHAddressHex('tokenAddress', tokenAddress); await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); assert.isETHAddressHex('toAddress', toAddress); @@ -199,6 +205,8 @@ export class TokenWrapper extends ContractWrapper { const txHash = await tokenContract.transfer.sendTransactionAsync(toAddress, amountInBaseUnits, { from: fromAddress, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, }); return txHash; } @@ -213,10 +221,11 @@ export class TokenWrapper extends ContractWrapper { * `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): + senderAddress: string, amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise { assert.isETHAddressHex('tokenAddress', tokenAddress); assert.isETHAddressHex('fromAddress', fromAddress); @@ -240,6 +249,8 @@ export class TokenWrapper extends ContractWrapper { fromAddress, toAddress, amountInBaseUnits, { from: senderAddress, + gas: txOpts.gasLimit, + gasPrice: txOpts.gasPrice, }, ); return txHash; diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts index af4f054f0..d187af01a 100644 --- a/packages/0x.js/src/types.ts +++ b/packages/0x.js/src/types.ts @@ -332,6 +332,7 @@ export interface TxOpts { from: string; gas?: number; value?: BigNumber; + gasPrice?: BigNumber; } export interface TokenAddressBySymbol { @@ -476,17 +477,27 @@ export interface ValidateOrderFillableOpts { * let's the user query the blockchain's state at an arbitrary point in time. In order for this to work, the * backing Ethereum node must keep the entire historical state of the chain (e.g setting `--pruning=archive` * flag when running Parity). + * gasPrice: Gas price to use for a transaction in */ export interface MethodOpts { defaultBlock?: Web3.BlockParam; } +/* + * gasPrice: Gas price in Wei to use for a transaction + * gasLimit: The amount of gas to send with a transaction + */ +export interface TransactionOpts { + gasPrice?: BigNumber; + gasLimit?: number; +} + /* * shouldValidate: Flag indicating whether the library should make attempts to validate a transaction before - * broadcasting it. For example, order has a valid signature, maker has sufficient funds, etc. + * broadcasting it. For example, order has a valid signature, maker has sufficient funds, etc. Default: true */ -export interface OrderTransactionOpts { - shouldValidate: boolean; +export interface OrderTransactionOpts extends TransactionOpts { + shouldValidate?: boolean; } export type FilterObject = Web3.FilterObject; -- cgit v1.2.3