Merge pull request #622 from 0xProject/geth-devnet-rebase-on-v2
Run contract tests against private Geth network
This commit is contained in:
commit
785b9811f3
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
```
|
||||
|
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,
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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),
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -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 () => {
|
||||
|
@ -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);
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () => {
|
||||
|
@ -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 () => {
|
||||
|
@ -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);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -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 () => {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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 () => {
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "0.4.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add optional parameter shouldUseFakeGasEstimate to Web3Config",
|
||||
"pr": 622
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.4.2",
|
||||
"changes": [
|
||||
|
@ -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 snapshotId = await this._web3Wrapper.takeSnapshotAsync();
|
||||
this._snapshotIdsStack.push(snapshotId);
|
||||
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 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`);
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_LIMIT));
|
||||
|
||||
if (config.shouldUseFakeGasEstimate) {
|
||||
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_LIMIT));
|
||||
}
|
||||
const logger = {
|
||||
log: (arg: any) => {
|
||||
fs.appendFileSync('ganache.log', `${arg}\n`);
|
||||
|
25
packages/devnet/Dockerfile
Normal file
25
packages/devnet/Dockerfile
Normal 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
110
packages/devnet/README.md
Normal 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.
|
61
packages/devnet/genesis.json
Normal file
61
packages/devnet/genesis.json
Normal 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"
|
||||
}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
@ -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}
|
11
packages/devnet/node0/password.txt
Normal file
11
packages/devnet/node0/password.txt
Normal file
@ -0,0 +1,11 @@
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
||||
password
|
42
packages/devnet/run.sh
Executable file
42
packages/devnet/run.sh
Executable 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
|
1171
packages/migrations/artifacts/2.0.0/MultiSigWallet.json
vendored
1171
packages/migrations/artifacts/2.0.0/MultiSigWallet.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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",
|
||||
|
@ -1,2 +1,2 @@
|
||||
export { Web3Wrapper } from './web3_wrapper';
|
||||
export { Web3Wrapper, uniqueVersionIds } from './web3_wrapper';
|
||||
export { Web3WrapperErrors } from './types';
|
||||
|
@ -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;
|
||||
|
43
yarn.lock
43
yarn.lock
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user