diff options
Diffstat (limited to 'packages/contracts/src/utils')
-rw-r--r-- | packages/contracts/src/utils/assertions.ts | 63 | ||||
-rw-r--r-- | packages/contracts/src/utils/constants.ts | 7 | ||||
-rw-r--r-- | packages/contracts/src/utils/coverage.ts | 1 | ||||
-rw-r--r-- | packages/contracts/src/utils/exchange_wrapper.ts | 14 | ||||
-rw-r--r-- | packages/contracts/src/utils/increase_time.ts | 31 | ||||
-rw-r--r-- | packages/contracts/src/utils/log_decoder.ts | 1 | ||||
-rw-r--r-- | packages/contracts/src/utils/match_order_tester.ts | 24 | ||||
-rw-r--r-- | packages/contracts/src/utils/multi_sig_wrapper.ts | 1 | ||||
-rw-r--r-- | packages/contracts/src/utils/order_factory.ts | 1 | ||||
-rw-r--r-- | packages/contracts/src/utils/order_utils.ts | 3 | ||||
-rw-r--r-- | packages/contracts/src/utils/transaction_factory.ts | 1 | ||||
-rw-r--r-- | packages/contracts/src/utils/types.ts | 4 | ||||
-rw-r--r-- | packages/contracts/src/utils/web3_wrapper.ts | 40 |
13 files changed, 150 insertions, 41 deletions
diff --git a/packages/contracts/src/utils/assertions.ts b/packages/contracts/src/utils/assertions.ts new file mode 100644 index 000000000..615e648f3 --- /dev/null +++ b/packages/contracts/src/utils/assertions.ts @@ -0,0 +1,63 @@ +import * as chai from 'chai'; +import * as _ from 'lodash'; + +import { constants } from './constants'; + +const expect = chai.expect; + +function _expectEitherErrorAsync<T>(p: Promise<T>, error1: string, error2: string): PromiseLike<void> { + return expect(p) + .to.be.rejected() + .then(e => { + expect(e).to.satisfy( + (err: Error) => _.includes(err.message, error1) || _.includes(err.message, error2), + `expected promise to reject with error message that includes "${error1}" or "${error2}", but got: ` + + `"${e.message}"\n`, + ); + }); +} + +/** + * Rejects if the given Promise does not reject with an error indicating + * insufficient funds. + * @param p the Promise which is expected to reject + * @returns a new Promise which will reject if the conditions are not met and + * otherwise resolve with no value. + */ +export function expectInsufficientFundsAsync<T>(p: Promise<T>): PromiseLike<void> { + return _expectEitherErrorAsync(p, 'insufficient funds', "sender doesn't have enough funds"); +} + +/** + * Rejects if the given Promise does not reject with a "revert" error or the + * given otherError. + * @param p the Promise which is expected to reject + * @param otherError the other error which is accepted as a valid reject error. + * @returns a new Promise which will reject if the conditions are not met and + * otherwise resolve with no value. + */ +export function expectRevertOrOtherErrorAsync<T>(p: Promise<T>, otherError: string): PromiseLike<void> { + return _expectEitherErrorAsync(p, constants.REVERT, otherError); +} + +/** + * Rejects if the given Promise does not reject with a "revert" or "always + * failing transaction" error. + * @param p the Promise which is expected to reject + * @returns a new Promise which will reject if the conditions are not met and + * otherwise resolve with no value. + */ +export function expectRevertOrAlwaysFailingTransactionAsync<T>(p: Promise<T>): PromiseLike<void> { + return expectRevertOrOtherErrorAsync(p, 'always failing transaction'); +} + +/** + * Rejects if the given Promise does not reject with a "revert" or "Contract + * call failed" error. + * @param p the Promise which is expected to reject + * @returns a new Promise which will reject if the conditions are not met and + * otherwise resolve with no value. + */ +export function expectRevertOrContractCallFailedAsync<T>(p: Promise<T>): PromiseLike<void> { + return expectRevertOrOtherErrorAsync<T>(p, 'Contract call failed'); +} diff --git a/packages/contracts/src/utils/constants.ts b/packages/contracts/src/utils/constants.ts index 9b0b92545..fa2a4af3c 100644 --- a/packages/contracts/src/utils/constants.ts +++ b/packages/contracts/src/utils/constants.ts @@ -19,6 +19,13 @@ const TESTRPC_PRIVATE_KEYS_STRINGS = [ export const constants = { INVALID_OPCODE: 'invalid opcode', REVERT: 'revert', + LIB_BYTES_GT_ZERO_LENGTH_REQUIRED: 'Length must be greater than 0.', + LIB_BYTES_GTE_4_LENGTH_REQUIRED: 'Length must be greater than or equal to 4.', + LIB_BYTES_GTE_20_LENGTH_REQUIRED: 'Length must be greater than or equal to 20.', + LIB_BYTES_GTE_32_LENGTH_REQUIRED: 'Length must be greater than or equal to 32.', + LIB_BYTES_INDEX_OUT_OF_BOUNDS: 'Specified array index is out of bounds.', + ERC20_INSUFFICIENT_BALANCE: 'Insufficient balance to complete transfer.', + ERC20_INSUFFICIENT_ALLOWANCE: 'Insufficient allowance to complete transfer.', TESTRPC_NETWORK_ID: 50, AWAIT_TRANSACTION_MINED_MS: 100, MAX_ETHERTOKEN_WITHDRAW_GAS: 43000, diff --git a/packages/contracts/src/utils/coverage.ts b/packages/contracts/src/utils/coverage.ts index a37939464..41c83f703 100644 --- a/packages/contracts/src/utils/coverage.ts +++ b/packages/contracts/src/utils/coverage.ts @@ -1,6 +1,5 @@ import { devConstants } from '@0xproject/dev-utils'; import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov'; -import * as fs from 'fs'; import * as _ from 'lodash'; let coverageSubprovider: CoverageSubprovider; diff --git a/packages/contracts/src/utils/exchange_wrapper.ts b/packages/contracts/src/utils/exchange_wrapper.ts index dd278e77c..7af243466 100644 --- a/packages/contracts/src/utils/exchange_wrapper.ts +++ b/packages/contracts/src/utils/exchange_wrapper.ts @@ -1,7 +1,7 @@ import { AssetProxyId, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; -import { LogEntry, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; import { ExchangeContract } from '../contract_wrappers/generated/exchange'; @@ -60,14 +60,14 @@ export class ExchangeWrapper { public async fillOrderNoThrowAsync( signedOrder: SignedOrder, from: string, - opts: { takerAssetFillAmount?: BigNumber } = {}, + opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); const txHash = await this._exchange.fillOrderNoThrow.sendTransactionAsync( params.order, params.takerAssetFillAmount, params.signature, - { from }, + { from, gas: opts.gas }, ); const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); return tx; @@ -105,14 +105,14 @@ export class ExchangeWrapper { public async batchFillOrdersNoThrowAsync( orders: SignedOrder[], from: string, - opts: { takerAssetFillAmounts?: BigNumber[] } = {}, + opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); const txHash = await this._exchange.batchFillOrdersNoThrow.sendTransactionAsync( params.orders, params.takerAssetFillAmounts, params.signatures, - { from }, + { from, gas: opts.gas }, ); const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); return tx; @@ -135,14 +135,14 @@ export class ExchangeWrapper { public async marketSellOrdersNoThrowAsync( orders: SignedOrder[], from: string, - opts: { takerAssetFillAmount: BigNumber }, + opts: { takerAssetFillAmount: BigNumber; gas?: number }, ): Promise<TransactionReceiptWithDecodedLogs> { const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); const txHash = await this._exchange.marketSellOrdersNoThrow.sendTransactionAsync( params.orders, params.takerAssetFillAmount, params.signatures, - { from }, + { from, gas: opts.gas }, ); const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); return tx; diff --git a/packages/contracts/src/utils/increase_time.ts b/packages/contracts/src/utils/increase_time.ts new file mode 100644 index 000000000..4565d8dbc --- /dev/null +++ b/packages/contracts/src/utils/increase_time.ts @@ -0,0 +1,31 @@ +import * as _ from 'lodash'; + +import { constants } from './constants'; +import { web3Wrapper } from './web3_wrapper'; + +let firstAccount: string | undefined; + +/** + * Increases time by the given number of seconds and then mines a block so that + * the current block timestamp has the offset applied. + * @param seconds the number of seconds by which to incrase the time offset. + * @returns a new Promise which will resolve with the new total time offset or + * reject if the time could not be increased. + */ +export async function increaseTimeAndMineBlockAsync(seconds: number): Promise<number> { + if (_.isUndefined(firstAccount)) { + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + firstAccount = accounts[0]; + } + + const offset = await web3Wrapper.increaseTimeAsync(seconds); + // Note: we need to send a transaction after increasing time so + // that a block is actually mined. The contract looks at the + // last mined block for the timestamp. + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ from: firstAccount, to: firstAccount, value: 0 }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + + return offset; +} diff --git a/packages/contracts/src/utils/log_decoder.ts b/packages/contracts/src/utils/log_decoder.ts index 07d10e69d..07127ba79 100644 --- a/packages/contracts/src/utils/log_decoder.ts +++ b/packages/contracts/src/utils/log_decoder.ts @@ -39,6 +39,7 @@ export class LogDecoder { } public decodeLogOrThrow<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog { const logWithDecodedArgsOrLog = this._abiDecoder.tryToDecodeLogOrNoop(log); + // tslint:disable-next-line:no-unnecessary-type-assertion if (_.isUndefined((logWithDecodedArgsOrLog as LogWithDecodedArgs<ArgsType>).args)) { throw new Error(`Unable to decode log: ${JSON.stringify(log)}`); } diff --git a/packages/contracts/src/utils/match_order_tester.ts b/packages/contracts/src/utils/match_order_tester.ts index 6170188bc..f4f7f965b 100644 --- a/packages/contracts/src/utils/match_order_tester.ts +++ b/packages/contracts/src/utils/match_order_tester.ts @@ -1,38 +1,21 @@ -import { BlockchainLifecycle } from '@0xproject/dev-utils'; -import { assetProxyUtils, crypto, orderHashUtils } from '@0xproject/order-utils'; +import { assetProxyUtils, orderHashUtils } from '@0xproject/order-utils'; import { AssetProxyId, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; -import { LogWithDecodedArgs } from 'ethereum-types'; -import ethUtil = require('ethereumjs-util'); import * as _ from 'lodash'; -import { DummyERC20TokenContract } from '../contract_wrappers/generated/dummy_e_r_c20_token'; -import { DummyERC721TokenContract } from '../contract_wrappers/generated/dummy_e_r_c721_token'; -import { ERC20ProxyContract } from '../contract_wrappers/generated/e_r_c20_proxy'; -import { ERC721ProxyContract } from '../contract_wrappers/generated/e_r_c721_proxy'; -import { - CancelContractEventArgs, - ExchangeContract, - FillContractEventArgs, -} from '../contract_wrappers/generated/exchange'; import { chaiSetup } from '../utils/chai_setup'; -import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; import { ERC721Wrapper } from '../utils/erc721_wrapper'; import { ExchangeWrapper } from '../utils/exchange_wrapper'; -import { OrderFactory } from '../utils/order_factory'; import { - ContractName, ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts, } from '../utils/types'; -import { provider, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); export class MatchOrderTester { private _exchangeWrapper: ExchangeWrapper; @@ -112,11 +95,6 @@ export class MatchOrderTester { initialTakerAssetFilledAmountLeft?: BigNumber, initialTakerAssetFilledAmountRight?: BigNumber, ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> { - // Test setup & verify preconditions - const makerAddressLeft = signedOrderLeft.makerAddress; - const makerAddressRight = signedOrderRight.makerAddress; - const feeRecipientAddressLeft = signedOrderLeft.feeRecipientAddress; - const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress; // Verify Left order preconditions const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderLeft), diff --git a/packages/contracts/src/utils/multi_sig_wrapper.ts b/packages/contracts/src/utils/multi_sig_wrapper.ts index 9971e8f6e..750466ce1 100644 --- a/packages/contracts/src/utils/multi_sig_wrapper.ts +++ b/packages/contracts/src/utils/multi_sig_wrapper.ts @@ -6,7 +6,6 @@ import * as _ from 'lodash'; import { AssetProxyOwnerContract } from '../contract_wrappers/generated/asset_proxy_owner'; import { MultiSigWalletContract } from '../contract_wrappers/generated/multi_sig_wallet'; -import { constants } from './constants'; import { LogDecoder } from './log_decoder'; export class MultiSigWrapper { diff --git a/packages/contracts/src/utils/order_factory.ts b/packages/contracts/src/utils/order_factory.ts index af411c01f..6e4c9a883 100644 --- a/packages/contracts/src/utils/order_factory.ts +++ b/packages/contracts/src/utils/order_factory.ts @@ -1,7 +1,6 @@ import { generatePseudoRandomSalt, orderHashUtils } from '@0xproject/order-utils'; import { Order, SignatureType, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; -import * as _ from 'lodash'; import { constants } from './constants'; import { signingUtils } from './signing_utils'; diff --git a/packages/contracts/src/utils/order_utils.ts b/packages/contracts/src/utils/order_utils.ts index 0d0329aa1..2a8791e4c 100644 --- a/packages/contracts/src/utils/order_utils.ts +++ b/packages/contracts/src/utils/order_utils.ts @@ -1,6 +1,5 @@ -import { Order, OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types'; +import { OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; -import ethUtil = require('ethereumjs-util'); import { CancelOrder, MatchOrder } from './types'; diff --git a/packages/contracts/src/utils/transaction_factory.ts b/packages/contracts/src/utils/transaction_factory.ts index 434611908..a060263b1 100644 --- a/packages/contracts/src/utils/transaction_factory.ts +++ b/packages/contracts/src/utils/transaction_factory.ts @@ -1,6 +1,5 @@ import { crypto, generatePseudoRandomSalt } from '@0xproject/order-utils'; import { SignatureType } from '@0xproject/types'; -import { BigNumber } from '@0xproject/utils'; import * as ethUtil from 'ethereumjs-util'; import { signingUtils } from './signing_utils'; diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 360e1fdbc..491890fa1 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -1,6 +1,6 @@ -import { Order, OrderWithoutExchangeAddress } from '@0xproject/types'; +import { OrderWithoutExchangeAddress } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; -import { AbiDefinition, ContractAbi } from 'ethereum-types'; +import { AbiDefinition } from 'ethereum-types'; export interface ERC20BalancesByOwner { [ownerAddress: string]: { diff --git a/packages/contracts/src/utils/web3_wrapper.ts b/packages/contracts/src/utils/web3_wrapper.ts index 1049ab967..df9bf88c8 100644 --- a/packages/contracts/src/utils/web3_wrapper.ts +++ b/packages/contracts/src/utils/web3_wrapper.ts @@ -1,19 +1,53 @@ import { devConstants, env, EnvVars, web3Factory } from '@0xproject/dev-utils'; import { prependSubprovider } from '@0xproject/subproviders'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; -import { Provider } from 'ethereum-types'; import { coverage } from './coverage'; -export const txDefaults = { +enum ProviderType { + Ganache = 'ganache', + Geth = 'geth', +} + +let testProvider: ProviderType; +switch (process.env.TEST_PROVIDER) { + case undefined: + testProvider = ProviderType.Ganache; + break; + case 'ganache': + testProvider = ProviderType.Ganache; + break; + case 'geth': + testProvider = ProviderType.Geth; + break; + default: + throw new Error(`Unknown TEST_PROVIDER: ${process.env.TEST_PROVIDER}`); +} + +const ganacheTxDefaults = { from: devConstants.TESTRPC_FIRST_ADDRESS, gas: devConstants.GAS_LIMIT, }; -const providerConfigs = { shouldUseInProcessGanache: true }; +const gethTxDefaults = { + from: devConstants.TESTRPC_FIRST_ADDRESS, +}; +export const txDefaults = testProvider === ProviderType.Ganache ? ganacheTxDefaults : gethTxDefaults; + +const gethConfigs = { + shouldUseInProcessGanache: false, + rpcUrl: 'http://localhost:8501', + shouldUseFakeGasEstimate: false, +}; +const ganacheConfigs = { + shouldUseInProcessGanache: true, +}; +const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : gethConfigs; + export const provider = web3Factory.getRpcProvider(providerConfigs); const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage); if (isCoverageEnabled) { const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); prependSubprovider(provider, coverageSubprovider); } + export const web3Wrapper = new Web3Wrapper(provider); |