merge v2-prototype
This commit is contained in:
@@ -50,7 +50,7 @@ contract MixinExchangeCore is
|
||||
|
||||
////// Core exchange functions //////
|
||||
|
||||
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
|
||||
/// @dev Cancels all orders created by sender with a salt less than or equal to the specified salt value.
|
||||
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
|
||||
function cancelOrdersUpTo(uint256 salt)
|
||||
external
|
||||
|
63
packages/contracts/src/utils/assertions.ts
Normal file
63
packages/contracts/src/utils/assertions.ts
Normal file
@@ -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');
|
||||
}
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
31
packages/contracts/src/utils/increase_time.ts
Normal file
31
packages/contracts/src/utils/increase_time.ts
Normal file
@@ -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;
|
||||
}
|
@@ -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)}`);
|
||||
}
|
||||
|
@@ -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),
|
||||
|
@@ -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 {
|
||||
|
@@ -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';
|
||||
|
@@ -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';
|
||||
|
||||
|
@@ -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';
|
||||
|
@@ -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]: {
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user