Merge pull request #622 from 0xProject/geth-devnet-rebase-on-v2

Run contract tests against private Geth network
This commit is contained in:
Alex Browne 2018-06-06 13:43:29 -07:00 committed by GitHub
commit 785b9811f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 1402 additions and 872 deletions

View File

@ -46,6 +46,7 @@
"wsrun": "^2.2.0"
},
"resolutions": {
"ethereumjs-tx": "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
"ethereumjs-tx": "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default",
"ethers": "0xproject/ethers.js#eip-838-reasons"
}
}

View File

@ -79,8 +79,7 @@ export class BaseContract {
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
} as any;
if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
const estimatedGas = await estimateGasAsync(txData);
txDataWithDefaults.gas = estimatedGas;
txDataWithDefaults.gas = await estimateGasAsync(txData);
}
return txDataWithDefaults;
}

View File

@ -63,3 +63,12 @@ yarn lint
```bash
yarn test
```
### Run Tests Against Geth
Follow the instructions in the README for the devnet package to start the
devnet.
```bash
TEST_PROVIDER=geth yarn test
```

View 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');
}

View File

@ -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,

View File

@ -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;

View 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;
}

View File

@ -5,15 +5,50 @@ 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);

View File

@ -6,6 +6,7 @@ import * as Web3 from 'web3';
import { MixinAuthorizableContract } from '../../src/contract_wrappers/generated/mixin_authorizable';
import { artifacts } from '../../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
@ -44,9 +45,9 @@ describe('Authorizable', () => {
});
describe('addAuthorizedAddress', () => {
it('should throw if not called by owner', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should allow owner to add an authorized address', async () => {
await web3Wrapper.awaitTransactionSuccessAsync(
@ -61,9 +62,9 @@ describe('Authorizable', () => {
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -73,11 +74,11 @@ describe('Authorizable', () => {
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
from: notOwner,
}),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should allow owner to remove an authorized address', async () => {
@ -96,11 +97,11 @@ describe('Authorizable', () => {
});
it('should throw if owner attempts to remove an address that is not authorized', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
from: owner,
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});

View File

@ -10,6 +10,7 @@ import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/d
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
@ -144,7 +145,7 @@ describe('Asset Transfer Proxies', () => {
constants.AWAIT_TRANSACTION_MINED_MS,
);
// Perform a transfer; expect this to fail.
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc20Proxy.transferFrom.sendTransactionAsync(
encodedProxyMetadata,
makerAddress,
@ -152,7 +153,7 @@ describe('Asset Transfer Proxies', () => {
transferAmount,
{ from: notAuthorized },
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if requesting address is not authorized', async () => {
@ -160,7 +161,7 @@ describe('Asset Transfer Proxies', () => {
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
// Perform a transfer from makerAddress to takerAddress
const amount = new BigNumber(10);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc20Proxy.transferFrom.sendTransactionAsync(
encodedProxyMetadata,
makerAddress,
@ -170,7 +171,7 @@ describe('Asset Transfer Proxies', () => {
from: notAuthorized,
},
),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -217,7 +218,7 @@ describe('Asset Transfer Proxies', () => {
const toAddresses = _.times(numTransfers, () => takerAddress);
const amounts = _.times(numTransfers, () => amount);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc20Proxy.batchTransferFrom.sendTransactionAsync(
assetMetadata,
fromAddresses,
@ -225,7 +226,7 @@ describe('Asset Transfer Proxies', () => {
amounts,
{ from: notAuthorized },
),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -276,7 +277,7 @@ describe('Asset Transfer Proxies', () => {
// Perform a transfer from makerAddress to takerAddress
const erc20Balances = await erc20Wrapper.getBalancesAsync();
const amount = new BigNumber(0);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc721Proxy.transferFrom.sendTransactionAsync(
encodedProxyMetadata,
makerAddress,
@ -284,7 +285,7 @@ describe('Asset Transfer Proxies', () => {
amount,
{ from: exchangeAddress },
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if transferring > 1 amount of a token', async () => {
@ -299,7 +300,7 @@ describe('Asset Transfer Proxies', () => {
// Perform a transfer from makerAddress to takerAddress
const erc20Balances = await erc20Wrapper.getBalancesAsync();
const amount = new BigNumber(500);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc721Proxy.transferFrom.sendTransactionAsync(
encodedProxyMetadata,
makerAddress,
@ -307,7 +308,7 @@ describe('Asset Transfer Proxies', () => {
amount,
{ from: exchangeAddress },
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if allowances are too low', async () => {
@ -325,7 +326,7 @@ describe('Asset Transfer Proxies', () => {
);
// Perform a transfer; expect this to fail.
const amount = new BigNumber(1);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc20Proxy.transferFrom.sendTransactionAsync(
encodedProxyMetadata,
makerAddress,
@ -335,7 +336,7 @@ describe('Asset Transfer Proxies', () => {
from: notAuthorized,
},
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if requesting address is not authorized', async () => {
@ -346,7 +347,7 @@ describe('Asset Transfer Proxies', () => {
);
// Perform a transfer from makerAddress to takerAddress
const amount = new BigNumber(1);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc721Proxy.transferFrom.sendTransactionAsync(
encodedProxyMetadata,
makerAddress,
@ -354,7 +355,7 @@ describe('Asset Transfer Proxies', () => {
amount,
{ from: notAuthorized },
),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -404,7 +405,7 @@ describe('Asset Transfer Proxies', () => {
const toAddresses = _.times(numTransfers, () => takerAddress);
const amounts = _.times(numTransfers, () => new BigNumber(1));
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
erc721Proxy.batchTransferFrom.sendTransactionAsync(
assetMetadata,
fromAddresses,
@ -412,7 +413,7 @@ describe('Asset Transfer Proxies', () => {
amounts,
{ from: notAuthorized },
),
).to.be.rejectedWith(constants.REVERT);
);
});
});

View File

@ -15,8 +15,13 @@ import {
} from '../src/contract_wrappers/generated/asset_proxy_owner';
import { MixinAuthorizableContract } from '../src/contract_wrappers/generated/mixin_authorizable';
import { artifacts } from '../src/utils/artifacts';
import {
expectRevertOrAlwaysFailingTransactionAsync,
expectRevertOrContractCallFailedAsync,
} from '../src/utils/assertions';
import { chaiSetup } from '../src/utils/chai_setup';
import { constants } from '../src/utils/constants';
import { increaseTimeAndMineBlockAsync } from '../src/utils/increase_time';
import { MultiSigWrapper } from '../src/utils/multi_sig_wrapper';
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
@ -101,7 +106,7 @@ describe('AssetProxyOwner', () => {
});
it('should throw if a null address is included in assetProxyContracts', async () => {
const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS];
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
AssetProxyOwnerContract.deployFrom0xArtifactAsync(
artifacts.AssetProxyOwner,
provider,
@ -111,7 +116,7 @@ describe('AssetProxyOwner', () => {
REQUIRED_APPROVALS,
SECONDS_TIME_LOCKED,
),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -120,9 +125,9 @@ describe('AssetProxyOwner', () => {
const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
owners[0],
);
return expect(
return expectRevertOrContractCallFailedAsync(
multiSig.isFunctionRemoveAuthorizedAddress.callAsync(notRemoveAuthorizedAddressData),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should return true if data is for removeAuthorizedAddress', async () => {
@ -139,9 +144,9 @@ describe('AssetProxyOwner', () => {
describe('registerAssetProxy', () => {
it('should throw if not called by multisig', async () => {
const isRegistered = true;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, { from: owners[0] }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should register an address if called by multisig after timelock', async () => {
@ -156,11 +161,12 @@ describe('AssetProxyOwner', () => {
registerAssetProxyData,
owners[0],
);
const log = submitTxRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId;
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
const registerLog = executeTxRes.logs[0] as LogWithDecodedArgs<AssetProxyRegistrationContractEventArgs>;
@ -187,7 +193,7 @@ describe('AssetProxyOwner', () => {
const txId = log.args.transactionId;
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
const failureLog = executeTxRes.logs[0] as LogWithDecodedArgs<ExecutionFailureContractEventArgs>;
@ -239,7 +245,7 @@ describe('AssetProxyOwner', () => {
await multiSigWrapper.confirmTransactionAsync(erc20AddAuthorizedAddressTxId, owners[1]);
await multiSigWrapper.confirmTransactionAsync(erc721AddAuthorizedAddressTxId, owners[1]);
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
await multiSigWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]);
await multiSigWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0]);
await multiSigWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0]);
@ -257,9 +263,9 @@ describe('AssetProxyOwner', () => {
const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if tx destination is not registered', async () => {
@ -276,9 +282,9 @@ describe('AssetProxyOwner', () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if tx data is not for removeAuthorizedAddress', async () => {
@ -296,9 +302,9 @@ describe('AssetProxyOwner', () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should execute removeAuthorizedAddress for registered address if fully confirmed', async () => {
@ -349,9 +355,9 @@ describe('AssetProxyOwner', () => {
const isExecuted = tx[3];
expect(isExecuted).to.equal(true);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
).to.be.rejectedWith(constants.REVERT);
);
});
});
});

View File

@ -6,6 +6,7 @@ import 'make-promises-safe';
import { WETH9Contract } from '../src/contract_wrappers/generated/weth9';
import { artifacts } from '../src/utils/artifacts';
import { expectInsufficientFundsAsync, expectRevertOrAlwaysFailingTransactionAsync } from '../src/utils/assertions';
import { chaiSetup } from '../src/utils/chai_setup';
import { constants } from '../src/utils/constants';
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
@ -45,9 +46,7 @@ describe('EtherToken', () => {
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const ethToDeposit = initEthBalance.plus(1);
return expect(etherToken.deposit.sendTransactionAsync({ value: ethToDeposit })).to.be.rejectedWith(
"ender doesn't have enough funds to send tx.",
);
return expectInsufficientFundsAsync(etherToken.deposit.sendTransactionAsync({ value: ethToDeposit }));
});
it('should convert deposited Ether to wrapped Ether tokens', async () => {
@ -76,8 +75,8 @@ describe('EtherToken', () => {
const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
const ethTokensToWithdraw = initEthTokenBalance.plus(1);
return expect(etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw),
);
});

View File

@ -18,6 +18,7 @@ import {
FillContractEventArgs,
} from '../../src/contract_wrappers/generated/exchange';
import { artifacts } from '../../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
@ -415,8 +416,8 @@ describe('Exchange core', () => {
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
});
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
@ -432,8 +433,8 @@ describe('Exchange core', () => {
const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
signedOrder.signature = invalidSigHex;
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
@ -442,8 +443,8 @@ describe('Exchange core', () => {
makerAssetAmount: new BigNumber(0),
});
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
@ -452,19 +453,19 @@ describe('Exchange core', () => {
takerAssetAmount: new BigNumber(0),
});
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
it('should throw if takerAssetFillAmount is 0', async () => {
signedOrder = orderFactory.newSignedOrder();
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount: new BigNumber(0),
}),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if maker erc20Balances are too low to fill order', async () => {
@ -472,8 +473,8 @@ describe('Exchange core', () => {
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
});
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
@ -481,9 +482,8 @@ describe('Exchange core', () => {
signedOrder = orderFactory.newSignedOrder({
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
});
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
@ -494,11 +494,8 @@ describe('Exchange core', () => {
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// HACK: `rejectWith` returns a "promise-like" type, but not an actual "Promise", so TSLint
// complains, even though we do need to `await` it. So we disable the TSLint error below.
// tslint:disable-next-line:await-promise
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
@ -509,11 +506,8 @@ describe('Exchange core', () => {
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// HACK: `rejectWith` returns a "promise-like" type, but not an actual "Promise", so TSLint
// complains, even though we do need to `await` it. So we disable the TSLint error below.
// tslint:disable-next-line:await-promise
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
@ -521,16 +515,16 @@ describe('Exchange core', () => {
signedOrder = orderFactory.newSignedOrder({
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
});
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
it('should throw if no value is filled', async () => {
signedOrder = orderFactory.newSignedOrder();
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
);
});
});
@ -542,8 +536,8 @@ describe('Exchange core', () => {
});
it('should throw if not sent by maker', async () => {
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress),
);
});
@ -552,8 +546,8 @@ describe('Exchange core', () => {
makerAssetAmount: new BigNumber(0),
});
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
);
});
@ -562,18 +556,18 @@ describe('Exchange core', () => {
takerAssetAmount: new BigNumber(0),
});
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
);
});
it('should be able to cancel a full order', async () => {
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
}),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should log 1 event with correct arguments', async () => {
@ -593,8 +587,8 @@ describe('Exchange core', () => {
it('should throw if already cancelled', async () => {
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
);
});
@ -602,8 +596,8 @@ describe('Exchange core', () => {
signedOrder = orderFactory.newSignedOrder({
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
});
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
);
});
@ -619,11 +613,11 @@ describe('Exchange core', () => {
});
const fillTakerAssetAmount2 = new BigNumber(1);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount: fillTakerAssetAmount2,
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -632,16 +626,16 @@ describe('Exchange core', () => {
const makerEpoch = new BigNumber(1);
await exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress);
const lesserMakerEpoch = new BigNumber(0);
return expect(exchangeWrapper.cancelOrdersUpToAsync(lesserMakerEpoch, makerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.cancelOrdersUpToAsync(lesserMakerEpoch, makerAddress),
);
});
it('should fail to set makerEpoch equal to existing makerEpoch', async () => {
const makerEpoch = new BigNumber(1);
await exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress);
return expect(exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress),
);
});
@ -675,7 +669,12 @@ describe('Exchange core', () => {
salt: new BigNumber(3),
}),
];
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress);
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 490000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();
const fillMakerAssetAmount = signedOrders[2].makerAssetAmount.add(signedOrders[3].makerAssetAmount);
@ -749,9 +748,9 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw when taker does not own the token with id takerAssetId', async () => {
@ -771,9 +770,9 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw when makerAssetAmount is greater than 1', async () => {
@ -793,9 +792,9 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw when takerAssetAmount is greater than 1', async () => {
@ -815,9 +814,9 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw on partial fill', async () => {
@ -837,9 +836,9 @@ describe('Exchange core', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => {

View File

@ -10,6 +10,7 @@ import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c2
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
import { TestAssetProxyDispatcherContract } from '../../src/contract_wrappers/generated/test_asset_proxy_dispatcher';
import { artifacts } from '../../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
@ -177,14 +178,14 @@ describe('AssetProxyDispatcher', () => {
const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
expect(proxyAddress).to.be.equal(erc20Proxy.address);
// The following transaction will throw because the currentAddress is no longer constants.NULL_ADDRESS
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(
AssetProxyId.ERC20,
erc20Proxy.address,
constants.NULL_ADDRESS,
{ from: owner },
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should be able to reset proxy address to NULL', async () => {
@ -218,26 +219,26 @@ describe('AssetProxyDispatcher', () => {
it('should throw if requesting address is not owner', async () => {
const prevProxyAddress = constants.NULL_ADDRESS;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(
AssetProxyId.ERC20,
erc20Proxy.address,
prevProxyAddress,
{ from: notOwner },
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if attempting to register a proxy to the incorrect id', async () => {
const prevProxyAddress = constants.NULL_ADDRESS;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(
AssetProxyId.ERC721,
erc20Proxy.address,
prevProxyAddress,
{ from: owner },
),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -307,7 +308,7 @@ describe('AssetProxyDispatcher', () => {
// Perform a transfer from makerAddress to takerAddress
const erc20Balances = await erc20Wrapper.getBalancesAsync();
const amount = new BigNumber(10);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
encodedProxyMetadata,
makerAddress,
@ -315,7 +316,7 @@ describe('AssetProxyDispatcher', () => {
amount,
{ from: owner },
),
).to.be.rejectedWith(constants.REVERT);
);
});
});
});

View File

@ -18,6 +18,7 @@ import {
FillContractEventArgs,
} from '../../src/contract_wrappers/generated/exchange';
import { artifacts } from '../../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
@ -639,9 +640,9 @@ describe('matchOrders', () => {
// Cancel left order
await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
// Match orders
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
).to.be.rejectedWith(constants.REVERT);
);
});
it('Should throw if right order is not fillable', async () => {
@ -665,9 +666,9 @@ describe('matchOrders', () => {
// Cancel right order
await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
// Match orders
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if there is not a positive spread', async () => {
@ -689,7 +690,7 @@ describe('matchOrders', () => {
feeRecipientAddress: feeRecipientAddressRight,
});
// Match orders
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
signedOrderLeft,
signedOrderRight,
@ -697,7 +698,7 @@ describe('matchOrders', () => {
erc20BalancesByOwner,
erc721TokenIdsByOwner,
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if the left maker asset is not equal to the right taker asset ', async () => {
@ -719,7 +720,7 @@ describe('matchOrders', () => {
feeRecipientAddress: feeRecipientAddressRight,
});
// Match orders
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
signedOrderLeft,
signedOrderRight,
@ -727,7 +728,7 @@ describe('matchOrders', () => {
erc20BalancesByOwner,
erc721TokenIdsByOwner,
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if the right maker asset is not equal to the left taker asset', async () => {
@ -749,7 +750,7 @@ describe('matchOrders', () => {
feeRecipientAddress: feeRecipientAddressRight,
});
// Match orders
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
signedOrderLeft,
signedOrderRight,
@ -757,7 +758,7 @@ describe('matchOrders', () => {
erc20BalancesByOwner,
erc721TokenIdsByOwner,
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should transfer correct amounts when left order maker asset is an ERC721 token', async () => {

View File

@ -11,6 +11,7 @@ import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c2
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
import { WhitelistContract } from '../../src/contract_wrappers/generated/whitelist';
import { artifacts } from '../../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
@ -126,8 +127,8 @@ describe('Exchange transactions', () => {
});
it('should throw if not called by specified sender', async () => {
return expect(exchangeWrapper.executeTransactionAsync(signedTx, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.executeTransactionAsync(signedTx, takerAddress),
);
});
@ -168,8 +169,8 @@ describe('Exchange transactions', () => {
it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => {
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
return expect(exchangeWrapper.executeTransactionAsync(signedTx, senderAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.executeTransactionAsync(signedTx, senderAddress),
);
});
@ -187,15 +188,15 @@ describe('Exchange transactions', () => {
});
it('should throw if not called by specified sender', async () => {
return expect(exchangeWrapper.executeTransactionAsync(signedTx, makerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.executeTransactionAsync(signedTx, makerAddress),
);
});
it('should cancel the order when signed by maker and called by sender', async () => {
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
return expect(exchangeWrapper.fillOrderAsync(signedOrder, senderAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrderAsync(signedOrder, senderAddress),
);
});
});
@ -244,7 +245,7 @@ describe('Exchange transactions', () => {
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
const takerAssetFillAmount = signedOrder.takerAssetAmount;
const salt = generatePseudoRandomSalt();
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
orderWithoutExchangeAddress,
takerAssetFillAmount,
@ -252,7 +253,7 @@ describe('Exchange transactions', () => {
signedOrder.signature,
{ from: takerAddress },
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should revert if taker has not been whitelisted', async () => {
@ -264,7 +265,7 @@ describe('Exchange transactions', () => {
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
const takerAssetFillAmount = signedOrder.takerAssetAmount;
const salt = generatePseudoRandomSalt();
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
orderWithoutExchangeAddress,
takerAssetFillAmount,
@ -272,7 +273,7 @@ describe('Exchange transactions', () => {
signedOrder.signature,
{ from: takerAddress },
),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should fill the order if maker and taker have been whitelisted', async () => {

View File

@ -15,6 +15,7 @@ import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
import { TokenRegistryContract } from '../../src/contract_wrappers/generated/token_registry';
import { artifacts } from '../../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
@ -172,8 +173,8 @@ describe('Exchange wrappers', () => {
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
});
return expect(exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
);
});
@ -184,8 +185,8 @@ describe('Exchange wrappers', () => {
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
});
return expect(exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
);
});
});
@ -197,12 +198,16 @@ describe('Exchange wrappers', () => {
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
});
const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 250000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();
const makerAssetFilledAmount = takerAssetFillAmount
.times(signedOrder.makerAssetAmount)
.dividedToIntegerBy(signedOrder.takerAssetAmount);
@ -212,6 +217,7 @@ describe('Exchange wrappers', () => {
const takerFee = signedOrder.takerFee
.times(makerAssetFilledAmount)
.dividedToIntegerBy(signedOrder.makerAssetAmount);
expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
);
@ -360,7 +366,13 @@ describe('Exchange wrappers', () => {
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
// Call Exchange
const takerAssetFillAmount = signedOrder.takerAssetAmount;
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, { takerAssetFillAmount });
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 270000,
});
// Verify post-conditions
const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
@ -485,11 +497,11 @@ describe('Exchange wrappers', () => {
await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
takerAssetFillAmounts,
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -535,6 +547,10 @@ describe('Exchange wrappers', () => {
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmounts,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();
@ -591,6 +607,10 @@ describe('Exchange wrappers', () => {
const newOrders = [invalidOrder, ...validOrders];
await exchangeWrapper.batchFillOrdersNoThrowAsync(newOrders, takerAddress, {
takerAssetFillAmounts,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 450000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();
@ -679,11 +699,11 @@ describe('Exchange wrappers', () => {
orderFactory.newSignedOrder(),
];
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -753,6 +773,10 @@ describe('Exchange wrappers', () => {
});
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();
@ -768,11 +792,11 @@ describe('Exchange wrappers', () => {
orderFactory.newSignedOrder(),
];
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -857,11 +881,11 @@ describe('Exchange wrappers', () => {
orderFactory.newSignedOrder(),
];
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});
@ -931,6 +955,10 @@ describe('Exchange wrappers', () => {
});
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
// delegatecall and swallow errors.
gas: 600000,
});
const newBalances = await erc20Wrapper.getBalancesAsync();
@ -946,11 +974,11 @@ describe('Exchange wrappers', () => {
orderFactory.newSignedOrder(),
];
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});

View File

@ -10,6 +10,7 @@ import * as Web3 from 'web3';
import { TestLibBytesContract } from '../../src/contract_wrappers/generated/test_lib_bytes';
import { artifacts } from '../../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync, expectRevertOrOtherErrorAsync } from '../../src/utils/assertions';
import { chaiSetup } from '../../src/utils/chai_setup';
import { constants } from '../../src/utils/constants';
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
@ -63,7 +64,10 @@ describe('LibBytes', () => {
describe('popByte', () => {
it('should revert if length is 0', async () => {
return expect(libBytes.publicPopByte.callAsync(constants.NULL_BYTES)).to.be.rejectedWith(constants.REVERT);
return expectRevertOrOtherErrorAsync(
libBytes.publicPopByte.callAsync(constants.NULL_BYTES),
constants.LIB_BYTES_GT_ZERO_LENGTH_REQUIRED,
);
});
it('should pop the last byte from the input and return it', async () => {
@ -77,8 +81,9 @@ describe('LibBytes', () => {
describe('popAddress', () => {
it('should revert if length is less than 20', async () => {
return expect(libBytes.publicPopAddress.callAsync(byteArrayShorterThan20Bytes)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicPopAddress.callAsync(byteArrayShorterThan20Bytes),
constants.LIB_BYTES_GTE_20_LENGTH_REQUIRED,
);
});
@ -162,16 +167,18 @@ describe('LibBytes', () => {
it('should fail if the byte array is too short to hold an address)', async () => {
const shortByteArray = '0xabcdef';
const offset = new BigNumber(0);
return expect(libBytes.publicReadAddress.callAsync(shortByteArray, offset)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicReadAddress.callAsync(shortByteArray, offset),
constants.LIB_BYTES_GTE_20_LENGTH_REQUIRED,
);
});
it('should fail if the length between the offset and end of the byte array is too short to hold an address)', async () => {
const byteArray = ethUtil.addHexPrefix(testAddress);
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
return expect(libBytes.publicReadAddress.callAsync(byteArray, badOffset)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicReadAddress.callAsync(byteArray, badOffset),
constants.LIB_BYTES_GTE_20_LENGTH_REQUIRED,
);
});
});
@ -206,15 +213,17 @@ describe('LibBytes', () => {
it('should fail if the byte array is too short to hold a bytes32)', async () => {
const offset = new BigNumber(0);
return expect(libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset),
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
);
});
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32)', async () => {
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
return expect(libBytes.publicReadBytes32.callAsync(testBytes32, badOffset)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicReadBytes32.callAsync(testBytes32, badOffset),
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
);
});
});
@ -253,8 +262,9 @@ describe('LibBytes', () => {
it('should fail if the byte array is too short to hold a uint256)', async () => {
const offset = new BigNumber(0);
return expect(libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset),
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
);
});
@ -263,8 +273,9 @@ describe('LibBytes', () => {
const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
const badOffset = new BigNumber(testUint256AsBuffer.byteLength);
return expect(libBytes.publicReadUint256.callAsync(byteArray, badOffset)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicReadUint256.callAsync(byteArray, badOffset),
constants.LIB_BYTES_GTE_32_LENGTH_REQUIRED,
);
});
});
@ -281,10 +292,12 @@ describe('LibBytes', () => {
*/
describe('readFirst4', () => {
// AssertionError: expected promise to be rejected with an error including 'revert' but it was fulfilled with '0x08c379a0'
it('should revert if byte array has a length < 4', async () => {
const byteArrayLessThan4Bytes = '0x010101';
return expect(libBytes.publicReadFirst4.callAsync(byteArrayLessThan4Bytes)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
libBytes.publicReadFirst4.callAsync(byteArrayLessThan4Bytes),
constants.LIB_BYTES_GTE_4_LENGTH_REQUIRED,
);
});
it('should return the first 4 bytes of a byte array of arbitrary length', async () => {

View File

@ -12,8 +12,10 @@ import {
SubmissionContractEventArgs,
} from '../src/contract_wrappers/generated/multi_sig_wallet_with_time_lock';
import { artifacts } from '../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../src/utils/assertions';
import { chaiSetup } from '../src/utils/chai_setup';
import { constants } from '../src/utils/constants';
import { increaseTimeAndMineBlockAsync } from '../src/utils/increase_time';
import { MultiSigWrapper } from '../src/utils/multi_sig_wrapper';
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
@ -69,9 +71,9 @@ describe('MultiSigWalletWithTimeLock', () => {
});
it('should throw when not called by wallet', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw without enough confirmations', async () => {
@ -80,10 +82,9 @@ describe('MultiSigWalletWithTimeLock', () => {
const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
const txId = log.args.transactionId;
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should set confirmation time with enough confirmations', async () => {
@ -148,14 +149,15 @@ describe('MultiSigWalletWithTimeLock', () => {
txId = log.args.transactionId;
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
});
it('should throw if it has enough confirmations but is not past the time lock', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should execute if it has enough confirmations and is past the time lock', async () => {
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
await web3Wrapper.awaitTransactionSuccessAsync(
await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
constants.AWAIT_TRANSACTION_MINED_MS,

View File

@ -9,6 +9,7 @@ import * as Web3 from 'web3';
import { TokenRegistryContract } from '../src/contract_wrappers/generated/token_registry';
import { artifacts } from '../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync } from '../src/utils/assertions';
import { chaiSetup } from '../src/utils/chai_setup';
import { constants } from '../src/utils/constants';
import { TokenRegWrapper } from '../src/utils/token_registry_wrapper';
@ -76,7 +77,7 @@ describe('TokenRegistry', () => {
describe('addToken', () => {
it('should throw when not called by owner', async () => {
return expect(tokenRegWrapper.addTokenAsync(token1, notOwner)).to.be.rejectedWith(constants.REVERT);
return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, notOwner));
});
it('should add token metadata when called by owner', async () => {
@ -88,19 +89,19 @@ describe('TokenRegistry', () => {
it('should throw if token already exists', async () => {
await tokenRegWrapper.addTokenAsync(token1, owner);
return expect(tokenRegWrapper.addTokenAsync(token1, owner)).to.be.rejectedWith(constants.REVERT);
return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, owner));
});
it('should throw if token address is null', async () => {
return expect(tokenRegWrapper.addTokenAsync(nullToken, owner)).to.be.rejectedWith(constants.REVERT);
return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(nullToken, owner));
});
it('should throw if name already exists', async () => {
await tokenRegWrapper.addTokenAsync(token1, owner);
const duplicateNameToken = _.assign({}, token2, { name: token1.name });
return expect(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
tokenRegWrapper.addTokenAsync(duplicateNameToken, owner),
);
});
@ -110,8 +111,8 @@ describe('TokenRegistry', () => {
symbol: token1.symbol,
});
return expect(tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner)).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrAlwaysFailingTransactionAsync(
tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner),
);
});
});
@ -137,9 +138,9 @@ describe('TokenRegistry', () => {
describe('setTokenName', () => {
it('should throw when not called by owner', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: notOwner }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should change the token name when called by owner', async () => {
@ -163,25 +164,25 @@ describe('TokenRegistry', () => {
it('should throw if the name already exists', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: owner }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if token does not exist', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.setTokenName.sendTransactionAsync(nullToken.address, token2.name, { from: owner }),
).to.be.rejectedWith(constants.REVERT);
);
});
});
describe('setTokenSymbol', () => {
it('should throw when not called by owner', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, {
from: notOwner,
}),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should change the token symbol when called by owner', async () => {
@ -203,28 +204,28 @@ describe('TokenRegistry', () => {
it('should throw if the symbol already exists', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, {
from: owner,
}),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if token does not exist', async () => {
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.setTokenSymbol.sendTransactionAsync(nullToken.address, token2.symbol, {
from: owner,
}),
).to.be.rejectedWith(constants.REVERT);
);
});
});
describe('removeToken', () => {
it('should throw if not called by owner', async () => {
const index = new BigNumber(0);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.removeToken.sendTransactionAsync(token1.address, index, { from: notOwner }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should remove token metadata when called by owner', async () => {
@ -241,17 +242,17 @@ describe('TokenRegistry', () => {
it('should throw if token does not exist', async () => {
const index = new BigNumber(0);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.removeToken.sendTransactionAsync(nullToken.address, index, { from: owner }),
).to.be.rejectedWith(constants.REVERT);
);
});
it('should throw if token at given index does not match address', async () => {
await tokenRegWrapper.addTokenAsync(token2, owner);
const incorrectIndex = new BigNumber(0);
return expect(
return expectRevertOrAlwaysFailingTransactionAsync(
tokenReg.removeToken.sendTransactionAsync(token2.address, incorrectIndex, { from: owner }),
).to.be.rejectedWith(constants.REVERT);
);
});
});
});

View File

@ -7,6 +7,7 @@ import * as Web3 from 'web3';
import { DummyERC20TokenContract } from '../src/contract_wrappers/generated/dummy_e_r_c20_token';
import { artifacts } from '../src/utils/artifacts';
import { expectRevertOrAlwaysFailingTransactionAsync, expectRevertOrOtherErrorAsync } from '../src/utils/assertions';
import { chaiSetup } from '../src/utils/chai_setup';
import { constants } from '../src/utils/constants';
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
@ -55,8 +56,9 @@ describe('UnlimitedAllowanceToken', () => {
it('should throw if owner has insufficient balance', async () => {
const ownerBalance = await token.balanceOf.callAsync(owner);
const amountToTransfer = ownerBalance.plus(1);
return expect(token.transfer.callAsync(spender, amountToTransfer, { from: owner })).to.be.rejectedWith(
constants.REVERT,
return expectRevertOrOtherErrorAsync(
token.transfer.callAsync(spender, amountToTransfer, { from: owner }),
constants.ERC20_INSUFFICIENT_BALANCE,
);
});
@ -93,11 +95,12 @@ describe('UnlimitedAllowanceToken', () => {
await token.approve.sendTransactionAsync(spender, amountToTransfer, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
return expect(
return expectRevertOrOtherErrorAsync(
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
from: spender,
}),
).to.be.rejectedWith(constants.REVERT);
constants.ERC20_INSUFFICIENT_BALANCE,
);
});
it('should throw if spender has insufficient allowance', async () => {
@ -108,11 +111,12 @@ describe('UnlimitedAllowanceToken', () => {
const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
expect(isSpenderAllowanceInsufficient).to.be.true();
return expect(
return expectRevertOrOtherErrorAsync(
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
from: spender,
}),
).to.be.rejectedWith(constants.REVERT);
constants.ERC20_INSUFFICIENT_ALLOWANCE,
);
});
it('should return true on a 0 value transfer', async () => {

View File

@ -1,4 +1,13 @@
[
{
"version": "0.4.3",
"changes": [
{
"note": "Add optional parameter shouldUseFakeGasEstimate to Web3Config",
"pr": 622
}
]
},
{
"version": "0.4.2",
"changes": [

View File

@ -1,6 +1,12 @@
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import { uniqueVersionIds, Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import * as Web3 from 'web3';
enum NodeType {
Geth = 'GETH',
Ganache = 'GANACHE',
}
export class BlockchainLifecycle {
private _web3Wrapper: Web3Wrapper;
private _snapshotIdsStack: number[];
@ -8,17 +14,47 @@ export class BlockchainLifecycle {
this._web3Wrapper = web3Wrapper;
this._snapshotIdsStack = [];
}
// TODO: In order to run these tests on an actual node, we should check if we are running against
// TestRPC, if so, use snapshots, otherwise re-deploy contracts before every test
public async startAsync(): Promise<void> {
const nodeType = await this._getNodeTypeAsync();
switch (nodeType) {
case NodeType.Ganache:
const snapshotId = await this._web3Wrapper.takeSnapshotAsync();
this._snapshotIdsStack.push(snapshotId);
break;
case NodeType.Geth:
const blockNumber = await this._web3Wrapper.getBlockNumberAsync();
this._snapshotIdsStack.push(blockNumber);
break;
default:
throw new Error(`Unknown node type: ${nodeType}`);
}
}
public async revertAsync(): Promise<void> {
const nodeType = await this._getNodeTypeAsync();
switch (nodeType) {
case NodeType.Ganache:
const snapshotId = this._snapshotIdsStack.pop() as number;
const didRevert = await this._web3Wrapper.revertSnapshotAsync(snapshotId);
if (!didRevert) {
throw new Error(`Snapshot with id #${snapshotId} failed to revert`);
}
break;
case NodeType.Geth:
const blockNumber = this._snapshotIdsStack.pop() as number;
await this._web3Wrapper.setHeadAsync(blockNumber);
break;
default:
throw new Error(`Unknown node type: ${nodeType}`);
}
}
private async _getNodeTypeAsync(): Promise<NodeType> {
const version = await this._web3Wrapper.getNodeVersionAsync();
if (_.includes(version, uniqueVersionIds.geth)) {
return NodeType.Geth;
} else if (_.includes(version, uniqueVersionIds.ganache)) {
return NodeType.Ganache;
} else {
throw new Error(`Unknown client version: ${version}`);
}
}
}

View File

@ -19,16 +19,22 @@ export interface Web3Config {
hasAddresses?: boolean; // default: true
shouldUseInProcessGanache?: boolean; // default: false
rpcUrl?: string; // default: localhost:8545
shouldUseFakeGasEstimate?: boolean; // default: true
}
export const web3Factory = {
getRpcProvider(config: Web3Config = {}): ProviderEngine {
const provider = new ProviderEngine();
const hasAddresses = _.isUndefined(config.hasAddresses) || config.hasAddresses;
config.shouldUseFakeGasEstimate =
_.isUndefined(config.shouldUseFakeGasEstimate) || config.shouldUseFakeGasEstimate;
if (!hasAddresses) {
provider.addProvider(new EmptyWalletSubprovider());
}
if (config.shouldUseFakeGasEstimate) {
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_LIMIT));
}
const logger = {
log: (arg: any) => {
fs.appendFileSync('ganache.log', `${arg}\n`);

View File

@ -0,0 +1,25 @@
FROM alpine:3.7
RUN \
apk add --update go git make gcc musl-dev linux-headers ca-certificates && \
# TODO(albrow): Change the Git URL and branch once we have all relvant PRs
# merged to upstream.
git clone --depth 1 --branch '0x-testing' https://github.com/0xProject/go-ethereum && \
(cd go-ethereum && make geth) && \
cp go-ethereum/build/bin/geth /geth && \
apk del go git make gcc musl-dev linux-headers && \
rm -rf /go-ethereum && rm -rf /var/cache/apk/*
RUN mkdir ~/devnet
WORKDIR ~/devnet
COPY genesis.json .
COPY node0/ ./node0
COPY run.sh .
RUN /geth --datadir node0/ init genesis.json
EXPOSE 8501
EXPOSE 30310
ENTRYPOINT ./run.sh

110
packages/devnet/README.md Normal file
View File

@ -0,0 +1,110 @@
## 0x Devnet
A private, single-node PoA Ethereum network for testing purposes only. It uses
Geth and the PoA implementation called "Clique".
## Installation
The devnet requires Docker to run (the latest version is recommended).
In the package root directory, run:
```
docker build -t 0x-devnet .
```
## Usage
To start the network, run:
```
docker run -it --rm -p 8501:8501 0x-devnet
```
Depending on your OS and how you installed docker, you may need to prefix any
docker commands with `sudo`.
The Docker container exposes the JSON RPC API at port 8501, and this is the
primary way you are expected to interact with the devnet. The following
endpoints are supported: `personal,db,eth,net,web3,txpool,miner,debug`.
You can stop the network with `docker stop` and it will automatically clean up
after itself. (`docker stop` typically requires you to use `docker ps` to find
the name of the currently running container).
### Configuration
The devnet network only has a single node and uses PoA instead of PoW. That
means that one node, called the "sealer", is the ultimate authority for
validating transactions and adding new blocks to the chain. Since there is no
PoW it also means that mining does not require significant computational
resources. You can learn more about PoA and the Geth-specific implementation
called "Clique" in [EIP-225](https://github.com/ethereum/EIPs/issues/225).
The address of the "sealer" is `0xe8816898d851d5b61b7f950627d04d794c07ca37`. The
password associated with the account is "password" and the (encrypted) private
keys are visible in the **node0/keystore** directory. This account is already
"unlocked" in the Geth node by default, so you can do things like sign and send
transactions from this account using the JSON RPC endpoints directly.
There are also a number of other addresses that have hard-coded starting
balances for testing purposes. You can see the details in the **genesis.json**
file. All of these accounts are also unlocked by default.
### Additional JSON RPC Methods
In addition to the
[standard JSON RPC methods](https://github.com/ethereum/wiki/wiki/JSON-RPC) and
the
[Geth Management API](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)
The devnet node supports some additional JSON RPC methods:
#### debug_increaseTime
Increases the timestamp of the next mined block.
##### Parameters
`Number` - The number of seconds by which to increase the time offset.
##### Returns
`Number` - The total number of seconds by which the time offset has been
increased (this includes all calls to `debug_increaseTime`).
##### Example
```js
// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"debug_increaseTime","params":[100],"id":67}'
// Result
{
"id":67,
"jsonrpc": "2.0",
"result": "5000"
}
```
### Mining
The node will automatically (nearly instantly) mine a block whenever new
transactions are added to the transaction pool. If there are no transactions in
the pool, it will wait.
To stop mining, use the
[`miner.stop`](https://github.com/ethereum/go-ethereum/wiki/Management-APIs#miner_stop)
method.
To start mining again, you can use the
[`miner.start`](https://github.com/ethereum/go-ethereum/wiki/Management-APIs#miner_start)
JSON RPC method.
## Contributing
We strongly recommend that the community help us make improvements and determine
the future direction of the protocol. To report bugs within this package, please
create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting
started.

View File

@ -0,0 +1,61 @@
{
"config": {
"chainId": 50,
"homesteadBlock": 1,
"eip150Block": 2,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 3,
"eip158Block": 3,
"byzantiumBlock": 4,
"clique": {
"period": 0,
"epoch": 30000
}
},
"nonce": "0x0",
"timestamp": "0x5af1ffac",
"extraData":
"0x0000000000000000000000000000000000000000000000000000000000000000e8816898d851d5b61b7f950627d04d794c07ca370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x4c4b400000",
"difficulty": "0x1",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"0xe8816898d851d5b61b7f950627d04d794c07ca37": {
"balance": "0x56BC75E2D63100000"
},
"0x5409ed021d9299bf6814279a6a1411a7e866a631": {
"balance": "0x56BC75E2D63100000"
},
"0x6ecbe1db9ef729cbe972c83fb886247691fb6beb": {
"balance": "0x56BC75E2D63100000"
},
"0xe36ea790bc9d7ab70c55260c66d52b1eca985f84": {
"balance": "0x56BC75E2D63100000"
},
"0xe834ec434daba538cd1b9fe1582052b880bd7e63": {
"balance": "0x56BC75E2D63100000"
},
"0x78dc5d2d739606d31509c31d654056a45185ecb6": {
"balance": "0x56BC75E2D63100000"
},
"0xa8dda8d7f5310e4a9e24f8eba77e091ac264f872": {
"balance": "0x56BC75E2D63100000"
},
"0x06cef8e666768cc40cc78cf93d9611019ddcb628": {
"balance": "0x56BC75E2D63100000"
},
"0x4404ac8bd8f9618d27ad2f1485aa1b2cfd82482d": {
"balance": "0x56BC75E2D63100000"
},
"0x7457d5e02197480db681d3fdf256c7aca21bdc12": {
"balance": "0x56BC75E2D63100000"
},
"0x91c987bf62d25945db517bdaa840a6c661374402": {
"balance": "0x56BC75E2D63100000"
}
},
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}

View File

@ -0,0 +1 @@
{"address":"5409ed021d9299bf6814279a6a1411a7e866a631","crypto":{"cipher":"aes-128-ctr","ciphertext":"7c7bdd62b303eb3a42d5d8e935825ed5a05a47cb2cef71e346c61b1bd582f1aa","cipherparams":{"iv":"7fd6c9d9f9893f2c480735b5386b6d75"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"79cc86edc3a668845a68fabb3913710b7504922e47aac8513ab3d6a28d090218"},"mac":"8a593ae0d0b964e47625bc964b6d389f5687f5bde631b4913136db4ab1b8083e"},"id":"29f637ba-6a65-4401-a0d1-30e1554bd776","version":3}

View File

@ -0,0 +1 @@
{"address":"6ecbe1db9ef729cbe972c83fb886247691fb6beb","crypto":{"cipher":"aes-128-ctr","ciphertext":"ecaf4f2839d74d92e2cb87c2fc7d52862661b46e697d70acfbe43f0893db73ed","cipherparams":{"iv":"7641c3a107228f8a901c07a07ea1f70d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c67c9fb30648df6985c0490b6603382147e7dc1ea28ca8c934af4a453ec0555b"},"mac":"985dca9ce65ad400fa4c9009742be2d409f402fe05203fc1278cfd1451729e8d"},"id":"e8634edc-08e6-415e-8d65-7985c4c4a05c","version":3}

View File

@ -0,0 +1 @@
{"address":"e36ea790bc9d7ab70c55260c66d52b1eca985f84","crypto":{"cipher":"aes-128-ctr","ciphertext":"49f89d7d612049f5f3581fc7c97d32ec9c9a2ca3c11165587139f16bfb29de6b","cipherparams":{"iv":"9767e0687a097c5b57e9cb30eec9bc0a"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"3e8f23332df99d519b602a0f6f4724338ba3fd9e7e313c337a92ffd1cafa19f1"},"mac":"4892051a669d45bb7de32a5eab63ee8fe52485a02218ce1806515da2adbd6584"},"id":"3488ad36-4a9d-4282-8651-7939b822429d","version":3}

View File

@ -0,0 +1 @@
{"address":"e834ec434daba538cd1b9fe1582052b880bd7e63","crypto":{"cipher":"aes-128-ctr","ciphertext":"a8ae3896739c63fc3bfe034277f6a1924a1c0ddc3f6747391dada8e61e15a928","cipherparams":{"iv":"f4f4d786cd3650a428a8bac5a6c824b1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"9acecc321bcab9b69ffdea494b8894ad0221c30f05c17d2302e315db8708ecc6"},"mac":"fc416b8f539fdc1e39e87a3bd2a69b04455875de701ced60cc8948b222171380"},"id":"0d9703e8-14fc-45d0-a425-2c40b8ae846a","version":3}

View File

@ -0,0 +1 @@
{"address":"78dc5d2d739606d31509c31d654056a45185ecb6","crypto":{"cipher":"aes-128-ctr","ciphertext":"25e90e593f08e9e3adc426c8685d90db5d1c04957e9dc8d5fab4ae30c3306b61","cipherparams":{"iv":"72ece22297a27363e795b678bcbd6be5"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"2201502b9d3c4e2076d9d15bfd9da3a6c75d9e2e574aabb29c3bc5a3b5ec55a5"},"mac":"13d709ed4bd2f5bf4973fc1373f8434835f0d12dc99b32c6fc14d9df7f41c62d"},"id":"3902dff4-5681-4646-b825-849f96efeec5","version":3}

View File

@ -0,0 +1 @@
{"address":"a8dda8d7f5310e4a9e24f8eba77e091ac264f872","crypto":{"cipher":"aes-128-ctr","ciphertext":"0d67c13cf0b130e8ffa1aaca5df372f727164e633f8e0e28a3e54d0884ffb568","cipherparams":{"iv":"619cd539cda9f40abb45bba00b5fe53d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"4effcd9b6fe71ee31cfe9057290154329b9af3acb6dcc46be7f78b5b9dcd3f42"},"mac":"c6eecd25944f4250b7b875d76bfbb60cc4e8db1d081621d1a2ddb72ea4e52a6d"},"id":"556bd3f1-1e5b-47a4-9b6e-448b9989d7d3","version":3}

View File

@ -0,0 +1 @@
{"address":"06cef8e666768cc40cc78cf93d9611019ddcb628","crypto":{"cipher":"aes-128-ctr","ciphertext":"38c9ca150932dc8c5ec5c65796425b2de98295cae64db08b816da2c06fc52c20","cipherparams":{"iv":"512127e8e606c481612473e7bc4d38f1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"16c4cabfd13cae2df66d8ff9acc7f503c95c808b00d0bb6a12932203889c679b"},"mac":"52297b496e8751627dea1ee17bf5cbea1926f90bcde3ffc8baa089184672f875"},"id":"31102097-86e4-4e19-ad73-03c3de67bf3b","version":3}

View File

@ -0,0 +1 @@
{"address":"4404ac8bd8f9618d27ad2f1485aa1b2cfd82482d","crypto":{"cipher":"aes-128-ctr","ciphertext":"ca7aedbacc960fc0fcb418606d7bdf042c36cc2808a5c94ac222cc0b44a9970d","cipherparams":{"iv":"3b1fe5da1cf5d6cd2ceaaf24c008c897"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a94e4d41d77ff6dc54beda30c7a46d8f3cc312ebeffa0352d679f7e3fc5301dc"},"mac":"9a82bf60103d05878f8af3c07765c22cba3df9b1c4376eaf859e47b805666e42"},"id":"ab68c67b-e15a-4ade-b3d9-2180a32b28fe","version":3}

View File

@ -0,0 +1 @@
{"address":"7457d5e02197480db681d3fdf256c7aca21bdc12","crypto":{"cipher":"aes-128-ctr","ciphertext":"720dcc2889c7b3636f9f659650181b0d46d82420460e23454277273f528baaee","cipherparams":{"iv":"1510028e2b9988d1a73b71cbb692d085"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"5db2b62f4d1f55a3f24c014c4f23f3ec9a2992dca6c2a89c24a566f99a079396"},"mac":"22c6fb134fd0a748195ea83e9ccb490ab2c9a3e8761f9d74ea6d02abbdeb8a43"},"id":"704c31f8-8ca2-4b49-9fdc-5923f5712dad","version":3}

View File

@ -0,0 +1 @@
{"address":"91c987bf62d25945db517bdaa840a6c661374402","crypto":{"cipher":"aes-128-ctr","ciphertext":"8f461f3c74643f382f7fc1f71719d5a89ed8cf75854d8a1b53e133997b53a386","cipherparams":{"iv":"cf595fb7680d36b4f5a01599ee54d2d1"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"73a9e599369d2bfaedd044559415147240c3517f6cd1dec8f77a98993d1ceaf8"},"mac":"c8be4dc59ad28d40f7b549a6b72834d149c84d67dc35e687676bbee0e07be395"},"id":"21cca6fb-7876-4e39-a986-a0a37f90da6d","version":3}

View File

@ -0,0 +1 @@
{"address":"e8816898d851d5b61b7f950627d04d794c07ca37","crypto":{"cipher":"aes-128-ctr","ciphertext":"1ff4add6955cba7ddaf29f66d7d21c5e1d714ef6191fbc651ae60f2ea3c95e8f","cipherparams":{"iv":"3ff869fbdbe1a523cdb327780365976e"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"7372dbae5fb318f8684902e099c311d4188721d677974d729711762c7ef6030c"},"mac":"485fa5dc701067782baa1589716a53110c7f917eb259e35ebca7265bbb7150b1"},"id":"89edb004-5b00-4607-a3af-a0d9ab9b1c34","version":3}

View File

@ -0,0 +1,11 @@
password
password
password
password
password
password
password
password
password
password
password

42
packages/devnet/run.sh Executable file
View File

@ -0,0 +1,42 @@
set -e
# Create log directory for Geth
mkdir -p /var/log
# Start Geth in background and redirect output to log file
/geth \
--verbosity 5 \
--datadir node0/ \
--syncmode 'full' \
--nat none \
--nodiscover \
--port 30310 \
--txpool.journal '' \
--rpc \
--rpcaddr '0.0.0.0' \
--rpcport 8501 \
--rpcapi 'personal,db,eth,net,web3,txpool,miner,debug' \
--networkid 50 \
--gasprice '2000000000' \
--targetgaslimit '0x4c4b400000' \
--mine \
--etherbase '0xe8816898d851d5b61b7f950627d04d794c07ca37' \
--unlock '0xe8816898d851d5b61b7f950627d04d794c07ca37,0x5409ed021d9299bf6814279a6a1411a7e866a631,0x6ecbe1db9ef729cbe972c83fb886247691fb6beb,0xe36ea790bc9d7ab70c55260c66d52b1eca985f84,0xe834ec434daba538cd1b9fe1582052b880bd7e63,0x78dc5d2d739606d31509c31d654056a45185ecb6,0xa8dda8d7f5310e4a9e24f8eba77e091ac264f872,0x06cef8e666768cc40cc78cf93d9611019ddcb628,0x4404ac8bd8f9618d27ad2f1485aa1b2cfd82482d,0x7457d5e02197480db681d3fdf256c7aca21bdc12,0x91c987bf62d25945db517bdaa840a6c661374402' \
--password=node0/password.txt \
> /var/log/geth &
# Wait for Geth to unlock the first account
sleep 10
# Send some transactions.
# HACK(albrow): 🐉 We have to do this so that debug.setHead works correctly.
# (Geth does not seem to like debug.setHead(0), so by sending some transactions
# we increase the current block number beyond 0). Additionally, some tests seem
# to break when there are fewer than 3 blocks in the chain. (We have no idea
# why, but it was consistently reproducible).
/geth --datadir node0/ attach --exec 'eth.sendTransaction({"from": "0x5409ED021D9299bf6814279A6A1411A7e866A631", "to": "0x84bd1cfa409cb0bb9b23b8b1a33515b4ac00a0af", "value": "0x1"})'
/geth --datadir node0/ attach --exec 'eth.sendTransaction({"from": "0x5409ED021D9299bf6814279A6A1411A7e866A631", "to": "0x84bd1cfa409cb0bb9b23b8b1a33515b4ac00a0af", "value": "0x1"})'
/geth --datadir node0/ attach --exec 'eth.sendTransaction({"from": "0x5409ED021D9299bf6814279A6A1411A7e866A631", "to": "0x84bd1cfa409cb0bb9b23b8b1a33515b4ac00a0af", "value": "0x1"})'
# Use tail to re-attach to the log file and actually see the output.
tail -f /var/log/geth

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,25 @@
[
{
"version": "0.7.0",
"changes": [
{
"note": "Add exported uniqueVersionIds object",
"pr": 622
},
{
"note": "Update increaseTimeAsync to work with Geth",
"pr": 622
},
{
"note": "Make callAsync throw if raw call result is 0x (null)",
"pr": 622
},
{
"note": "Add new setHeadAsync method",
"pr": 622
}
]
},
{
"timestamp": 1527009133,
"version": "0.6.4",

View File

@ -1,2 +1,2 @@
export { Web3Wrapper } from './web3_wrapper';
export { Web3Wrapper, uniqueVersionIds } from './web3_wrapper';
export { Web3WrapperErrors } from './types';

View File

@ -21,6 +21,13 @@ import { Web3WrapperErrors } from './types';
const BASE_TEN = 10;
// These are unique identifiers contained in the response of the
// web3_clientVersion call.
export const uniqueVersionIds = {
geth: 'Geth',
ganache: 'EthereumJS TestRPC',
};
/**
* A wrapper around the Web3.js 0.x library that provides a consistent, clean promise-based interface.
*/
@ -254,11 +261,20 @@ export class Web3Wrapper {
await this._sendRawPayloadAsync<string>({ method: 'evm_mine', params: [] });
}
/**
* Increase the next blocks timestamp on TestRPC/Ganache local node
* Increase the next blocks timestamp on TestRPC/Ganache or Geth local node.
* Will throw if provider is neither TestRPC/Ganache or Geth.
* @param timeDelta Amount of time to add in seconds
*/
public async increaseTimeAsync(timeDelta: number): Promise<void> {
await this._sendRawPayloadAsync<string>({ method: 'evm_increaseTime', params: [timeDelta] });
public async increaseTimeAsync(timeDelta: number): Promise<number> {
// Detect Geth vs. Ganache and use appropriate endpoint.
const version = await this.getNodeVersionAsync();
if (_.includes(version, uniqueVersionIds.geth)) {
return this._sendRawPayloadAsync<number>({ method: 'debug_increaseTime', params: [timeDelta] });
} else if (_.includes(version, uniqueVersionIds.ganache)) {
return this._sendRawPayloadAsync<number>({ method: 'evm_increaseTime', params: [timeDelta] });
} else {
throw new Error(`Unknown client version: ${version}`);
}
}
/**
* Retrieve smart contract logs for a given filter
@ -281,7 +297,6 @@ export class Web3Wrapper {
};
const payload = {
jsonrpc: '2.0',
id: this._jsonRpcRequestId++,
method: 'eth_getLogs',
params: [serializedFilter],
};
@ -315,6 +330,9 @@ export class Web3Wrapper {
*/
public async callAsync(callData: CallData, defaultBlock?: BlockParam): Promise<string> {
const rawCallResult = await promisify<string>(this._web3.eth.call)(callData, defaultBlock);
if (rawCallResult === '0x') {
throw new Error('Contract call failed (returned null)');
}
return rawCallResult;
}
/**
@ -403,8 +421,20 @@ export class Web3Wrapper {
}
return receipt;
}
/**
* Calls the 'debug_setHead' JSON RPC method, which sets the current head of
* the local chain by block number. Note, this is a destructive action and
* may severely damage your chain. Use with extreme caution. As of now, this
* is only supported by Geth. It sill throw if the 'debug_setHead' method is
* not supported.
* @param blockNumber The block number to reset to.
*/
public async setHeadAsync(blockNumber: number): Promise<void> {
await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [this._web3.toHex(blockNumber)] });
}
private async _sendRawPayloadAsync<A>(payload: Partial<JSONRPCRequestPayload>): Promise<A> {
const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider);
payload.id = this._jsonRpcRequestId++;
const response = await promisify<JSONRPCResponsePayload>(sendAsync)(payload);
const result = response.result;
return result;

View File

@ -4068,14 +4068,7 @@ ethereum-common@^0.0.18:
version "0.0.18"
resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f"
ethereumjs-abi@^0.6.4:
version "0.6.5"
resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz#5a637ef16ab43473fa72a29ad90871405b3f5241"
dependencies:
bn.js "^4.10.0"
ethereumjs-util "^4.3.0"
"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
ethereumjs-abi@^0.6.4, "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
version "0.6.5"
resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf"
dependencies:
@ -4124,7 +4117,7 @@ ethereumjs-tx@0xProject/ethereumjs-tx#fake-tx-include-signature-by-default, ethe
ethereum-common "^0.0.18"
ethereumjs-util "^5.0.0"
ethereumjs-util@^4.0.1, ethereumjs-util@^4.3.0, ethereumjs-util@^4.4.0:
ethereumjs-util@^4.0.1, ethereumjs-util@^4.4.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz#3e9428b317eebda3d7260d854fddda954b1f1bc6"
dependencies:
@ -4190,9 +4183,9 @@ ethereumjs-wallet@~0.6.0:
utf8 "^2.1.1"
uuid "^2.0.1"
ethers@^3.0.15:
version "3.0.15"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-3.0.15.tgz#7cdea4e23025681f69f575bf481b227315e0e7ab"
ethers@0xproject/ethers.js#eip-838-reasons, ethers@^3.0.15:
version "3.0.18"
resolved "https://codeload.github.com/0xproject/ethers.js/tar.gz/b91342bd200d142af0165d6befddf783c8ae8447"
dependencies:
aes-js "3.0.0"
bn.js "^4.4.0"
@ -12569,7 +12562,7 @@ web3-net@1.0.0-beta.34:
web3-core-method "1.0.0-beta.34"
web3-utils "1.0.0-beta.34"
web3-provider-engine@^13.3.2:
web3-provider-engine@^13.3.2, web3-provider-engine@^13.6.5:
version "13.8.0"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df"
dependencies:
@ -12593,30 +12586,6 @@ web3-provider-engine@^13.3.2:
xhr "^2.2.0"
xtend "^4.0.1"
web3-provider-engine@^13.6.5:
version "13.6.6"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.6.6.tgz#7d8972ffcd31e103bd2ce8a521b1b7da08cb173f"
dependencies:
async "^2.5.0"
clone "^2.0.0"
eth-block-tracker "^2.2.2"
eth-sig-util "^1.4.2"
ethereumjs-block "^1.2.2"
ethereumjs-tx "^1.2.0"
ethereumjs-util "^5.1.1"
ethereumjs-vm "^2.0.2"
fetch-ponyfill "^4.0.0"
json-rpc-error "^2.0.0"
json-stable-stringify "^1.0.1"
promise-to-callback "^1.0.0"
readable-stream "^2.2.9"
request "^2.67.0"
semaphore "^1.0.3"
solc "^0.4.2"
tape "^4.4.0"
xhr "^2.2.0"
xtend "^4.0.1"
web3-provider-engine@^14.0.4:
version "14.0.4"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.0.4.tgz#6f96b71ea1b3a76cc67cd52007116c8d4b64465b"