diff options
author | Leonid <logvinov.leon@gmail.com> | 2017-11-29 04:37:33 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-29 04:37:33 +0800 |
commit | a98d6bf496ae8d1698fd63a3a7a4db756e743cb1 (patch) | |
tree | 3018bdd100d8280056c459b8ac41ff08b7115dc7 /packages/0x.js/src | |
parent | bbcf669bd9bc73924436e9ea41fe393b8d23a863 (diff) | |
parent | 353abffba9afd73d70fce47fee2f2d6067c6c8ae (diff) | |
download | dexon-sol-tools-a98d6bf496ae8d1698fd63a3a7a4db756e743cb1.tar dexon-sol-tools-a98d6bf496ae8d1698fd63a3a7a4db756e743cb1.tar.gz dexon-sol-tools-a98d6bf496ae8d1698fd63a3a7a4db756e743cb1.tar.bz2 dexon-sol-tools-a98d6bf496ae8d1698fd63a3a7a4db756e743cb1.tar.lz dexon-sol-tools-a98d6bf496ae8d1698fd63a3a7a4db756e743cb1.tar.xz dexon-sol-tools-a98d6bf496ae8d1698fd63a3a7a4db756e743cb1.tar.zst dexon-sol-tools-a98d6bf496ae8d1698fd63a3a7a4db756e743cb1.zip |
Merge pull request #235 from 0xProject/feature/gasPriceGasLimit
Add optional config for gasPrice and gasLimit for every transaction sending method
Diffstat (limited to 'packages/0x.js/src')
-rw-r--r-- | packages/0x.js/src/contract.ts | 43 | ||||
-rw-r--r-- | packages/0x.js/src/contract_wrappers/ether_token_wrapper.ts | 18 | ||||
-rw-r--r-- | packages/0x.js/src/contract_wrappers/exchange_wrapper.ts | 153 | ||||
-rw-r--r-- | packages/0x.js/src/contract_wrappers/token_wrapper.ts | 41 | ||||
-rw-r--r-- | packages/0x.js/src/subproviders/empty_wallet_subprovider.ts | 27 | ||||
-rw-r--r-- | packages/0x.js/src/types.ts | 16 |
6 files changed, 125 insertions, 173 deletions
diff --git a/packages/0x.js/src/contract.ts b/packages/0x.js/src/contract.ts index e9c49c9f1..a4ee03910 100644 --- a/packages/0x.js/src/contract.ts +++ b/packages/0x.js/src/contract.ts @@ -5,6 +5,10 @@ import * as Web3 from 'web3'; import {AbiType} from './types'; +// HACK: Gas estimates on testrpc don't take into account gas refunds. +// Our calls can trigger max 8 gas refunds for SSTORE per transaction for 15k gas each which gives 120k. +const GAS_MARGIN = 120000; + export class Contract implements Web3.ContractInstance { public address: string; public abi: Web3.ContractAbi; @@ -34,9 +38,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,28 +52,40 @@ export class Contract implements Web3.ContractInstance { this[eventAbi.name] = this.contract[eventAbi.name]; }); } - private promisifyWithDefaultParams(fn: (...args: any[]) => void): (...args: any[]) => Promise<any> { + private promisifyWithDefaultParams( + web3CbStyleFunction: (...args: any[]) => void, + estimateGasAsync: (...args: any[]) => Promise<number>, + ): (...args: any[]) => Promise<any> { 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<Web3.TxData> = {}; - if (this.isTxData(lastArg)) { + if (!_.isUndefined(lastArg) && this.isTxData(lastArg)) { txData = args.pop(); } + // Gas amount sourced with the following priorities: + // 1. Optional param passed in to public method call + // 2. Global config passed in at library instantiation + // 3. Gas estimate calculation + safety margin + const removeUndefinedProperties = _.pickBy; txData = { - ...this.defaults, - ...txData, + ...removeUndefinedProperties(this.defaults), + ...removeUndefinedProperties(txData), }; - const callback = (err: Error, data: any) => { - if (_.isNull(err)) { - resolve(data); - } else { + if (_.isUndefined(txData.gas)) { + try { + const estimatedGas = await estimateGasAsync.apply(this.contract, [...args, txData]); + const gas = estimatedGas + GAS_MARGIN; + txData.gas = gas; + } catch (err) { reject(err); + return; } - }; + } + const callback = (err: Error, data: any) => _.isNull(err) ? resolve(data) : reject(err); 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..ede0460bd 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,13 @@ 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<string> { + public async depositAsync( + amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {}, + ): Promise<string> { assert.isValidBaseUnitAmount('amountInWei', amountInWei); await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); @@ -41,6 +44,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 +54,12 @@ 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<string> { + public async withdrawAsync( + amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {}, + ): Promise<string> { assert.isValidBaseUnitAmount('amountInWei', amountInWei); await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); @@ -62,6 +70,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..273b348ff 100644 --- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts @@ -169,16 +169,16 @@ export class ExchangeWrapper extends ContractWrapper { public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, shouldThrowOnInsufficientBalanceOrAllowance: boolean, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise<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; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? + SHOULD_VALIDATE_BY_DEFAULT : + orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -188,18 +188,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 +198,8 @@ export class ExchangeWrapper extends ContractWrapper { signedOrder.ecSignature.s, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -236,7 +225,7 @@ export class ExchangeWrapper extends ContractWrapper { public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber, shouldThrowOnInsufficientBalanceOrAllowance: boolean, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise<string> { + orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress); assert.hasAtMostOneUniqueValue(takerTokenAddresses, @@ -248,9 +237,9 @@ 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 = _.isUndefined(orderTransactionOpts.shouldValidate) ? + SHOULD_VALIDATE_BY_DEFAULT : + orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -278,18 +267,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 +277,8 @@ export class ExchangeWrapper extends ContractWrapper { sArray, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -328,7 +306,7 @@ export class ExchangeWrapper extends ContractWrapper { public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[], shouldThrowOnInsufficientBalanceOrAllowance: boolean, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise<string> { + orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); const exchangeContractAddresses = _.map( orderFillRequests, @@ -338,9 +316,9 @@ 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 = _.isUndefined(orderTransactionOpts.shouldValidate) ? + SHOULD_VALIDATE_BY_DEFAULT : + orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -370,18 +348,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 +358,8 @@ export class ExchangeWrapper extends ContractWrapper { sArray, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -411,16 +378,16 @@ export class ExchangeWrapper extends ContractWrapper { @decorators.contractCallErrorHandler public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise<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; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? + SHOULD_VALIDATE_BY_DEFAULT : + orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -429,18 +396,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 +405,8 @@ export class ExchangeWrapper extends ContractWrapper { signedOrder.ecSignature.s, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -467,7 +423,7 @@ export class ExchangeWrapper extends ContractWrapper { @decorators.contractCallErrorHandler public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[], takerAddress: string, - orderTransactionOpts?: OrderTransactionOpts): Promise<string> { + orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema); const exchangeContractAddresses = _.map( @@ -482,9 +438,9 @@ export class ExchangeWrapper extends ContractWrapper { } const exchangeInstance = await this._getExchangeContractAsync(); - const shouldValidate = _.isUndefined(orderTransactionOpts) ? - SHOULD_VALIDATE_BY_DEFAULT : - orderTransactionOpts.shouldValidate; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? + SHOULD_VALIDATE_BY_DEFAULT : + orderTransactionOpts.shouldValidate; if (shouldValidate) { const zrxTokenAddress = this.getZRXTokenAddress(); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); @@ -509,18 +465,6 @@ export class ExchangeWrapper extends ContractWrapper { // 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, @@ -530,7 +474,8 @@ export class ExchangeWrapper extends ContractWrapper { sParams, { from: takerAddress, - gas, + gas: orderTransactionOpts.gasLimit, + gasPrice: orderTransactionOpts.gasPrice, }, ); return txHash; @@ -546,16 +491,16 @@ export class ExchangeWrapper extends ContractWrapper { @decorators.contractCallErrorHandler public async cancelOrderAsync(order: Order|SignedOrder, cancelTakerTokenAmount: BigNumber, - orderTransactionOpts?: OrderTransactionOpts): Promise<string> { + 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; + const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ? + SHOULD_VALIDATE_BY_DEFAULT : + orderTransactionOpts.shouldValidate; if (shouldValidate) { const orderHash = utils.getOrderHashHex(order); const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash); @@ -564,21 +509,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 +531,7 @@ export class ExchangeWrapper extends ContractWrapper { */ @decorators.contractCallErrorHandler public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[], - orderTransactionOpts?: OrderTransactionOpts): Promise<string> { + orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> { assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests, schemas.orderCancellationRequestsSchema); const exchangeContractAddresses = _.map( @@ -606,9 +544,9 @@ 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 = _.isUndefined(orderTransactionOpts.shouldValidate) ? + SHOULD_VALIDATE_BY_DEFAULT : + orderTransactionOpts.shouldValidate; if (shouldValidate) { for (const orderCancellationRequest of orderCancellationRequests) { const orderHash = utils.getOrderHashHex(orderCancellationRequest.order); @@ -633,21 +571,14 @@ export class ExchangeWrapper extends ContractWrapper { // 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, + 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<string> { + amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): 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 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<string> { + spenderAddress: string, txOpts: TransactionOpts = {}): Promise<string> { 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<string> { + amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { 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<string> { + public async setUnlimitedProxyAllowanceAsync( + tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {}, + ): Promise<string> { 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<string> { + amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> { 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<string> { 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/subproviders/empty_wallet_subprovider.ts b/packages/0x.js/src/subproviders/empty_wallet_subprovider.ts deleted file mode 100644 index 2993bc801..000000000 --- a/packages/0x.js/src/subproviders/empty_wallet_subprovider.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {JSONRPCPayload} from '../types'; - -/* - * This class implements the web3-provider-engine subprovider interface and returns - * that the provider has no addresses when queried. - * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js - */ -export class EmptyWalletSubProvider { - // This method needs to be here to satisfy the interface but linter wants it to be static. - // tslint:disable-next-line:prefer-function-over-method - public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) { - switch (payload.method) { - case 'eth_accounts': - end(null, []); - return; - - default: - next(); - return; - } - } - // Required to implement this method despite not needing it for this subprovider - // tslint:disable-next-line:prefer-function-over-method - public setEngine(engine: any) { - // noop - } -} diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts index 91a5978ea..5363b02ff 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 { @@ -484,11 +485,20 @@ export interface MethodOpts { } /* + * 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; |