move log tests to @0x/abi-gen; delete exchange_wrapper_test (#2160)
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -97,12 +97,6 @@ contract AbiGenDummy
|
||||
return ecrecover(prefixedHash, v, r, s);
|
||||
}
|
||||
|
||||
event Withdrawal(address indexed _owner, uint _value);
|
||||
|
||||
function withdraw(uint wad) public {
|
||||
emit Withdrawal(msg.sender, wad);
|
||||
}
|
||||
|
||||
// test: generated code should normalize address inputs to lowercase
|
||||
// add extra inputs to make sure it works with address in any position
|
||||
function withAddressInput(address x, uint256 a, uint256 b, address y, uint256 c)
|
||||
@@ -113,8 +107,6 @@ contract AbiGenDummy
|
||||
return x;
|
||||
}
|
||||
|
||||
event AnEvent(uint8 param);
|
||||
|
||||
function acceptsBytes(bytes memory a) public pure {}
|
||||
|
||||
/// @dev a method that accepts an array of bytes
|
||||
@@ -180,6 +172,22 @@ contract AbiGenDummy
|
||||
function overloadedMethod(int a) public pure {}
|
||||
function overloadedMethod(string memory a) public pure {}
|
||||
|
||||
|
||||
event Withdrawal(address indexed _owner, uint _value);
|
||||
|
||||
function withdraw(uint wad) public {
|
||||
emit Withdrawal(msg.sender, wad);
|
||||
}
|
||||
|
||||
event SimpleEvent(bytes someBytes, string someString);
|
||||
|
||||
function emitSimpleEvent() public {
|
||||
emit SimpleEvent(
|
||||
hex'12345678',
|
||||
"lorem"
|
||||
);
|
||||
}
|
||||
|
||||
// begin tests for `decodeTransactionData`, `decodeReturnData`
|
||||
/// @dev complex input is dynamic and more difficult to decode than simple input.
|
||||
struct ComplexInput {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,11 +31,11 @@ import { assert } from '@0x/assert';
|
||||
import * as ethers from 'ethers';
|
||||
// tslint:enable:no-unused-variable
|
||||
|
||||
export type AbiGenDummyEventArgs = AbiGenDummyWithdrawalEventArgs | AbiGenDummyAnEventEventArgs;
|
||||
export type AbiGenDummyEventArgs = AbiGenDummyWithdrawalEventArgs | AbiGenDummySimpleEventEventArgs;
|
||||
|
||||
export enum AbiGenDummyEvents {
|
||||
Withdrawal = 'Withdrawal',
|
||||
AnEvent = 'AnEvent',
|
||||
SimpleEvent = 'SimpleEvent',
|
||||
}
|
||||
|
||||
export interface AbiGenDummyWithdrawalEventArgs extends DecodedLogArgs {
|
||||
@@ -43,8 +43,9 @@ export interface AbiGenDummyWithdrawalEventArgs extends DecodedLogArgs {
|
||||
_value: BigNumber;
|
||||
}
|
||||
|
||||
export interface AbiGenDummyAnEventEventArgs extends DecodedLogArgs {
|
||||
param: number;
|
||||
export interface AbiGenDummySimpleEventEventArgs extends DecodedLogArgs {
|
||||
someBytes: string;
|
||||
someString: string;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
@@ -1809,6 +1810,147 @@ export class AbiGenDummyContract extends BaseContract {
|
||||
return abiDecodedReturnData;
|
||||
},
|
||||
};
|
||||
public emitSimpleEvent = {
|
||||
/**
|
||||
* Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write
|
||||
* Ethereum operation and will cost gas.
|
||||
* @param txData Additional data for transaction
|
||||
* @returns The hash of the transaction
|
||||
*/
|
||||
async sendTransactionAsync(txData?: Partial<TxData> | undefined): Promise<string> {
|
||||
const self = (this as any) as AbiGenDummyContract;
|
||||
const encodedData = self._strictEncodeArguments('emitSimpleEvent()', []);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...txData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
self.emitSimpleEvent.estimateGasAsync.bind(self),
|
||||
);
|
||||
if (txDataWithDefaults.from !== undefined) {
|
||||
txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase();
|
||||
}
|
||||
|
||||
const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
return txHash;
|
||||
},
|
||||
/**
|
||||
* Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting.
|
||||
* If the transaction was mined, but reverted, an error is thrown.
|
||||
* @param txData Additional data for transaction
|
||||
* @param pollingIntervalMs Interval at which to poll for success
|
||||
* @returns A promise that resolves when the transaction is successful
|
||||
*/
|
||||
awaitTransactionSuccessAsync(
|
||||
txData?: Partial<TxData>,
|
||||
pollingIntervalMs?: number,
|
||||
timeoutMs?: number,
|
||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
||||
const self = (this as any) as AbiGenDummyContract;
|
||||
const txHashPromise = self.emitSimpleEvent.sendTransactionAsync(txData);
|
||||
return new PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>(
|
||||
txHashPromise,
|
||||
(async (): Promise<TransactionReceiptWithDecodedLogs> => {
|
||||
// When the transaction hash resolves, wait for it to be mined.
|
||||
return self._web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await txHashPromise,
|
||||
pollingIntervalMs,
|
||||
timeoutMs,
|
||||
);
|
||||
})(),
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments.
|
||||
* @param txData Additional data for transaction
|
||||
* @returns The hash of the transaction
|
||||
*/
|
||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
||||
const self = (this as any) as AbiGenDummyContract;
|
||||
const encodedData = self._strictEncodeArguments('emitSimpleEvent()', []);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...txData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
if (txDataWithDefaults.from !== undefined) {
|
||||
txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase();
|
||||
}
|
||||
|
||||
const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
return gas;
|
||||
},
|
||||
async validateAndSendTransactionAsync(txData?: Partial<TxData> | undefined): Promise<string> {
|
||||
await (this as any).emitSimpleEvent.callAsync(txData);
|
||||
const txHash = await (this as any).emitSimpleEvent.sendTransactionAsync(txData);
|
||||
return txHash;
|
||||
},
|
||||
/**
|
||||
* Sends a read-only call to the contract method. Returns the result that would happen if one were to send an
|
||||
* Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas
|
||||
* since they don't modify state.
|
||||
*/
|
||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
|
||||
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
|
||||
schemas.addressSchema,
|
||||
schemas.numberSchema,
|
||||
schemas.jsNumber,
|
||||
]);
|
||||
if (defaultBlock !== undefined) {
|
||||
assert.isBlockParam('defaultBlock', defaultBlock);
|
||||
}
|
||||
const self = (this as any) as AbiGenDummyContract;
|
||||
const encodedData = self._strictEncodeArguments('emitSimpleEvent()', []);
|
||||
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
|
||||
{
|
||||
to: self.address,
|
||||
...callData,
|
||||
data: encodedData,
|
||||
},
|
||||
self._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
callDataWithDefaults.from = callDataWithDefaults.from
|
||||
? callDataWithDefaults.from.toLowerCase()
|
||||
: callDataWithDefaults.from;
|
||||
|
||||
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
|
||||
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
|
||||
const abiEncoder = self._lookupAbiEncoder('emitSimpleEvent()');
|
||||
// tslint:disable boolean-naming
|
||||
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
|
||||
// tslint:enable boolean-naming
|
||||
return result;
|
||||
},
|
||||
/**
|
||||
* Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before
|
||||
* sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used
|
||||
* to create a 0x transaction (see protocol spec for more details).
|
||||
*/
|
||||
getABIEncodedTransactionData(): string {
|
||||
const self = (this as any) as AbiGenDummyContract;
|
||||
const abiEncodedTransactionData = self._strictEncodeArguments('emitSimpleEvent()', []);
|
||||
return abiEncodedTransactionData;
|
||||
},
|
||||
getABIDecodedTransactionData(callData: string): void {
|
||||
const self = (this as any) as AbiGenDummyContract;
|
||||
const abiEncoder = self._lookupAbiEncoder('emitSimpleEvent()');
|
||||
// tslint:disable boolean-naming
|
||||
const abiDecodedCallData = abiEncoder.strictDecode<void>(callData);
|
||||
return abiDecodedCallData;
|
||||
},
|
||||
getABIDecodedReturnData(returnData: string): void {
|
||||
const self = (this as any) as AbiGenDummyContract;
|
||||
const abiEncoder = self._lookupAbiEncoder('emitSimpleEvent()');
|
||||
// tslint:disable boolean-naming
|
||||
const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<void>(returnData);
|
||||
return abiDecodedReturnData;
|
||||
},
|
||||
};
|
||||
/**
|
||||
* a method that returns a struct
|
||||
*/
|
||||
@@ -2712,6 +2854,15 @@ export class AbiGenDummyContract extends BaseContract {
|
||||
stateMutability: 'pure',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
constant: false,
|
||||
inputs: [],
|
||||
name: 'emitSimpleEvent',
|
||||
outputs: [],
|
||||
payable: false,
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
constant: true,
|
||||
inputs: [],
|
||||
@@ -2822,12 +2973,17 @@ export class AbiGenDummyContract extends BaseContract {
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
name: 'param',
|
||||
type: 'uint8',
|
||||
name: 'someBytes',
|
||||
type: 'bytes',
|
||||
indexed: false,
|
||||
},
|
||||
{
|
||||
name: 'someString',
|
||||
type: 'string',
|
||||
indexed: false,
|
||||
},
|
||||
],
|
||||
name: 'AnEvent',
|
||||
name: 'SimpleEvent',
|
||||
outputs: [],
|
||||
type: 'event',
|
||||
},
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0x/dev-utils';
|
||||
import { Web3ProviderEngine } from '@0x/subproviders';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
|
||||
import { BlockParamLiteral, Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
import * as ChaiBigNumber from 'chai-bignumber';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as Sinon from 'sinon';
|
||||
import { constants } from 'websocket';
|
||||
|
||||
import { AbiGenDummyContract, AbiGenDummyEvents, artifacts, TestLibDummyContract } from '../src';
|
||||
import {
|
||||
AbiGenDummyContract,
|
||||
AbiGenDummyEvents,
|
||||
AbiGenDummyWithdrawalEventArgs,
|
||||
artifacts,
|
||||
TestLibDummyContract,
|
||||
} from '../src';
|
||||
|
||||
const txDefaults = {
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
@@ -163,6 +169,45 @@ describe('AbiGenDummy Contract', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLogsAsync', () => {
|
||||
const blockRange = {
|
||||
fromBlock: 0,
|
||||
toBlock: BlockParamLiteral.Latest,
|
||||
};
|
||||
it('should get logs with decoded args emitted by EventWithStruct', async () => {
|
||||
await abiGenDummy.emitSimpleEvent.awaitTransactionSuccessAsync();
|
||||
const eventName = AbiGenDummyEvents.SimpleEvent;
|
||||
const indexFilterValues = {};
|
||||
const logs = await abiGenDummy.getLogsAsync(eventName, blockRange, indexFilterValues);
|
||||
expect(logs).to.have.length(1);
|
||||
expect(logs[0].event).to.be.equal(eventName);
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
await abiGenDummy.emitSimpleEvent.awaitTransactionSuccessAsync();
|
||||
const differentEventName = AbiGenDummyEvents.Withdrawal;
|
||||
const indexFilterValues = {};
|
||||
const logs = await abiGenDummy.getLogsAsync(differentEventName, blockRange, indexFilterValues);
|
||||
expect(logs).to.have.length(0);
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
const [addressOne, addressTwo] = await web3Wrapper.getAvailableAddressesAsync();
|
||||
await abiGenDummy.withdraw.awaitTransactionSuccessAsync(new BigNumber(1), { from: addressOne });
|
||||
await abiGenDummy.withdraw.awaitTransactionSuccessAsync(new BigNumber(1), { from: addressTwo });
|
||||
const eventName = AbiGenDummyEvents.Withdrawal;
|
||||
const indexFilterValues = {
|
||||
_owner: addressOne,
|
||||
};
|
||||
const logs = await abiGenDummy.getLogsAsync<AbiGenDummyWithdrawalEventArgs>(
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
expect(args._owner).to.be.equal(addressOne);
|
||||
});
|
||||
});
|
||||
|
||||
describe('withAddressInput', () => {
|
||||
it('should normalize address inputs to lowercase', async () => {
|
||||
const xAddress = devConstants.TESTRPC_FIRST_ADDRESS.toUpperCase();
|
||||
|
||||
@@ -50,8 +50,12 @@
|
||||
"@0x/assert": "^2.1.5",
|
||||
"@0x/contracts-test-utils": "^3.1.15",
|
||||
"@0x/coordinator-server": "^0.1.3",
|
||||
"@0x/dev-utils": "^2.3.2",
|
||||
"@0x/fill-scenarios": "^3.0.18",
|
||||
"@0x/json-schemas": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/migrations": "^4.3.1",
|
||||
"@0x/subproviders": "^5.0.3",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@0x/types": "^2.4.2",
|
||||
"@0x/utils": "^4.5.1",
|
||||
@@ -62,7 +66,6 @@
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^2.1.5",
|
||||
"ethers": "~4.0.4",
|
||||
"lodash": "^4.17.11",
|
||||
"mocha": "^6.2.0",
|
||||
"nock": "^10.0.6",
|
||||
@@ -76,11 +79,8 @@
|
||||
"@0x/base-contract": "^5.3.3",
|
||||
"@0x/contract-addresses": "^3.1.0",
|
||||
"@0x/contract-artifacts": "^2.2.1",
|
||||
"@0x/dev-utils": "^2.3.2",
|
||||
"@0x/fill-scenarios": "^3.0.18",
|
||||
"@0x/migrations": "^4.3.1",
|
||||
"@0x/order-utils": "^8.3.1",
|
||||
"@0x/subproviders": "^5.0.3",
|
||||
"ethers": "~4.0.4",
|
||||
"http-status-codes": "^1.3.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,550 +0,0 @@
|
||||
import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
|
||||
import { FillScenarios } from '@0x/fill-scenarios';
|
||||
import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils';
|
||||
import { DoneCallback, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import { BlockParamLiteral } from 'ethereum-types';
|
||||
import 'mocha';
|
||||
|
||||
import { ContractWrappers, ExchangeCancelEventArgs, ExchangeEvents, ExchangeFillEventArgs, OrderStatus } from '../src';
|
||||
import { DecodedLogEvent } from '../src/types';
|
||||
import { _getDefaultContractAddresses } from '../src/utils/contract_addresses';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
import { migrateOnceAsync } from './utils/migrate';
|
||||
import { tokenUtils } from './utils/token_utils';
|
||||
import { provider, web3Wrapper } from './utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('ExchangeWrapper', () => {
|
||||
let contractWrappers: ContractWrappers;
|
||||
let userAddresses: string[];
|
||||
let zrxTokenAddress: string;
|
||||
let fillScenarios: FillScenarios;
|
||||
let exchangeContractAddress: string;
|
||||
let makerTokenAddress: string;
|
||||
let takerTokenAddress: string;
|
||||
let makerAddress: string;
|
||||
let anotherMakerAddress: string;
|
||||
let takerAddress: string;
|
||||
let makerAssetData: string;
|
||||
let takerAssetData: string;
|
||||
const fillableAmount = new BigNumber(5);
|
||||
const takerTokenFillAmount = new BigNumber(5);
|
||||
let signedOrder: SignedOrder;
|
||||
let anotherSignedOrder: SignedOrder;
|
||||
|
||||
before(async () => {
|
||||
const contractAddresses = await migrateOnceAsync();
|
||||
await blockchainLifecycle.startAsync();
|
||||
const config = {
|
||||
networkId: constants.TESTRPC_NETWORK_ID,
|
||||
contractAddresses,
|
||||
blockPollingIntervalMs: 10,
|
||||
};
|
||||
contractWrappers = new ContractWrappers(provider, config);
|
||||
exchangeContractAddress = contractWrappers.exchange.address;
|
||||
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
zrxTokenAddress = contractAddresses.zrxToken;
|
||||
fillScenarios = new FillScenarios(
|
||||
provider,
|
||||
userAddresses,
|
||||
zrxTokenAddress,
|
||||
exchangeContractAddress,
|
||||
contractWrappers.erc20Proxy.address,
|
||||
contractWrappers.erc721Proxy.address,
|
||||
);
|
||||
[, makerAddress, takerAddress, , anotherMakerAddress] = userAddresses;
|
||||
[makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
|
||||
[makerAssetData, takerAssetData] = [
|
||||
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
|
||||
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
|
||||
];
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerAssetData,
|
||||
takerAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerAssetData,
|
||||
takerAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('fill order(s)', () => {
|
||||
describe('#fillOrderAsync', () => {
|
||||
it('should fill a valid order', async () => {
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#fillOrderNoThrowAsync', () => {
|
||||
it('should fill a valid order', async () => {
|
||||
await contractWrappers.exchange.fillOrderNoThrow.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder);
|
||||
expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled);
|
||||
});
|
||||
});
|
||||
describe('#fillOrKillOrderAsync', () => {
|
||||
it('should fill or kill a valid order', async () => {
|
||||
await contractWrappers.exchange.fillOrKillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#batchFillOrdersAsync', () => {
|
||||
it('should fill a batch of valid orders', async () => {
|
||||
const signedOrders = [signedOrder, anotherSignedOrder];
|
||||
const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount];
|
||||
await contractWrappers.exchange.batchFillOrders.awaitTransactionSuccessAsync(
|
||||
signedOrders,
|
||||
takerAssetFillAmounts,
|
||||
signedOrders.map(o => o.signature),
|
||||
{ from: takerAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#marketBuyOrdersAsync', () => {
|
||||
it('should maker buy', async () => {
|
||||
const signedOrders = [signedOrder, anotherSignedOrder];
|
||||
const makerAssetFillAmount = takerTokenFillAmount;
|
||||
await contractWrappers.exchange.marketBuyOrders.awaitTransactionSuccessAsync(
|
||||
signedOrders,
|
||||
makerAssetFillAmount,
|
||||
signedOrders.map(o => o.signature),
|
||||
{ from: takerAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#marketBuyOrdersNoThrowAsync', () => {
|
||||
it('should no throw maker buy', async () => {
|
||||
const signedOrders = [signedOrder, anotherSignedOrder];
|
||||
const makerAssetFillAmount = takerTokenFillAmount;
|
||||
await contractWrappers.exchange.marketBuyOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
signedOrders,
|
||||
makerAssetFillAmount,
|
||||
signedOrders.map(o => o.signature),
|
||||
{ from: takerAddress },
|
||||
);
|
||||
const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder);
|
||||
expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled);
|
||||
});
|
||||
});
|
||||
describe('#marketSellOrdersAsync', () => {
|
||||
it('should maker sell', async () => {
|
||||
const signedOrders = [signedOrder, anotherSignedOrder];
|
||||
const takerAssetFillAmount = takerTokenFillAmount;
|
||||
await contractWrappers.exchange.marketSellOrders.awaitTransactionSuccessAsync(
|
||||
signedOrders,
|
||||
takerAssetFillAmount,
|
||||
signedOrders.map(o => o.signature),
|
||||
{ from: takerAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#marketSellOrdersNoThrowAsync', () => {
|
||||
it('should no throw maker sell', async () => {
|
||||
const signedOrders = [signedOrder, anotherSignedOrder];
|
||||
const takerAssetFillAmount = takerTokenFillAmount;
|
||||
await contractWrappers.exchange.marketSellOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
signedOrders,
|
||||
takerAssetFillAmount,
|
||||
signedOrders.map(o => o.signature),
|
||||
{ from: takerAddress },
|
||||
);
|
||||
const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder);
|
||||
expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled);
|
||||
});
|
||||
});
|
||||
describe('#batchFillOrdersNoThrowAsync', () => {
|
||||
it('should fill a batch of valid orders', async () => {
|
||||
const signedOrders = [signedOrder, anotherSignedOrder];
|
||||
const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount];
|
||||
await contractWrappers.exchange.batchFillOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
signedOrders,
|
||||
takerAssetFillAmounts,
|
||||
signedOrders.map(o => o.signature),
|
||||
{ from: takerAddress },
|
||||
);
|
||||
let orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder);
|
||||
expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled);
|
||||
orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(anotherSignedOrder);
|
||||
expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled);
|
||||
});
|
||||
});
|
||||
describe('#batchFillOrKillOrdersAsync', () => {
|
||||
it('should fill or kill a batch of valid orders', async () => {
|
||||
const signedOrders = [signedOrder, anotherSignedOrder];
|
||||
const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount];
|
||||
await contractWrappers.exchange.batchFillOrKillOrders.awaitTransactionSuccessAsync(
|
||||
signedOrders,
|
||||
takerAssetFillAmounts,
|
||||
signedOrders.map(o => o.signature),
|
||||
{ from: takerAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#matchOrdersAsync', () => {
|
||||
it('should match two valid ordersr', async () => {
|
||||
const matchingSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
takerAssetData,
|
||||
makerAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
await contractWrappers.exchange.matchOrders.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
matchingSignedOrder,
|
||||
signedOrder.signature,
|
||||
matchingSignedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('cancel order(s)', () => {
|
||||
describe('#cancelOrderAsync', () => {
|
||||
it('should cancel a valid order', async () => {
|
||||
await contractWrappers.exchange.cancelOrder.awaitTransactionSuccessAsync(signedOrder, {
|
||||
from: makerAddress,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#batchCancelOrdersAsync', () => {
|
||||
it('should cancel a batch of valid orders', async () => {
|
||||
const orders = [signedOrder, anotherSignedOrder];
|
||||
await contractWrappers.exchange.batchCancelOrders.awaitTransactionSuccessAsync(orders, {
|
||||
from: makerAddress,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#cancelOrdersUpTo/getOrderEpochAsync', () => {
|
||||
it('should cancel orders up to target order epoch', async () => {
|
||||
const targetOrderEpoch = new BigNumber(42);
|
||||
await contractWrappers.exchange.cancelOrdersUpTo.awaitTransactionSuccessAsync(targetOrderEpoch, {
|
||||
from: makerAddress,
|
||||
});
|
||||
const orderEpoch = await contractWrappers.exchange.orderEpoch.callAsync(
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
);
|
||||
expect(orderEpoch).to.be.bignumber.equal(targetOrderEpoch.plus(1));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#getOrderInfoAsync', () => {
|
||||
it('should get the order info', async () => {
|
||||
const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder);
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
expect(orderInfo.orderHash).to.be.equal(orderHash);
|
||||
});
|
||||
});
|
||||
describe('#getOrdersInfoAsync', () => {
|
||||
it('should get the orders info', async () => {
|
||||
const ordersInfo = await contractWrappers.exchange.getOrdersInfo.callAsync([
|
||||
signedOrder,
|
||||
anotherSignedOrder,
|
||||
]);
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
expect(ordersInfo[0].orderHash).to.be.equal(orderHash);
|
||||
const anotherOrderHash = orderHashUtils.getOrderHashHex(anotherSignedOrder);
|
||||
expect(ordersInfo[1].orderHash).to.be.equal(anotherOrderHash);
|
||||
});
|
||||
});
|
||||
describe('#isValidSignature', () => {
|
||||
it('should check if the signature is valid', async () => {
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
let isValid = await contractWrappers.exchange.isValidSignature.callAsync(
|
||||
orderHash,
|
||||
signedOrder.makerAddress,
|
||||
signedOrder.signature,
|
||||
);
|
||||
expect(isValid).to.be.true();
|
||||
isValid = await contractWrappers.exchange.isValidSignature.callAsync(
|
||||
orderHash,
|
||||
signedOrder.takerAddress,
|
||||
signedOrder.signature,
|
||||
);
|
||||
expect(isValid).to.be.false();
|
||||
});
|
||||
});
|
||||
describe('#isAllowedValidatorAsync', () => {
|
||||
it('should check if the validator is allowed', async () => {
|
||||
const signerAddress = makerAddress;
|
||||
const validatorAddress = constants.NULL_ADDRESS;
|
||||
const isAllowed = await contractWrappers.exchange.allowedValidators.callAsync(
|
||||
signerAddress,
|
||||
validatorAddress,
|
||||
);
|
||||
expect(isAllowed).to.be.false();
|
||||
});
|
||||
});
|
||||
describe('#setSignatureValidatorApproval', () => {
|
||||
it('should set signature validator approval', async () => {
|
||||
const validatorAddress = constants.NULL_ADDRESS;
|
||||
const isApproved = true;
|
||||
const senderAddress = makerAddress;
|
||||
await contractWrappers.exchange.setSignatureValidatorApproval.awaitTransactionSuccessAsync(
|
||||
validatorAddress,
|
||||
isApproved,
|
||||
{ from: senderAddress },
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#isTransactionExecutedAsync', () => {
|
||||
it('should check if the transaction is executed', async () => {
|
||||
const transactionHash = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const isExecuted = await contractWrappers.exchange.transactions.callAsync(transactionHash);
|
||||
expect(isExecuted).to.be.false();
|
||||
});
|
||||
});
|
||||
describe('#getAssetProxyBySignatureAsync', () => {
|
||||
it('should fill or kill a valid order', async () => {
|
||||
const erc20ProxyId = await contractWrappers.erc20Proxy.getProxyId.callAsync();
|
||||
const erc20ProxyAddressById = await contractWrappers.exchange.getAssetProxy.callAsync(erc20ProxyId);
|
||||
const erc20ProxyAddress = contractWrappers.erc20Proxy.address;
|
||||
expect(erc20ProxyAddressById).to.be.equal(erc20ProxyAddress);
|
||||
const erc721ProxyId = await contractWrappers.erc721Proxy.getProxyId.callAsync();
|
||||
const erc721ProxyAddressById = await contractWrappers.exchange.getAssetProxy.callAsync(erc721ProxyId);
|
||||
const erc721ProxyAddress = contractWrappers.erc721Proxy.address;
|
||||
expect(erc721ProxyAddressById).to.be.equal(erc721ProxyAddress);
|
||||
});
|
||||
});
|
||||
describe('#preSign/isPresigned', () => {
|
||||
it('should preSign the hash', async () => {
|
||||
const senderAddress = takerAddress;
|
||||
const hash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const signerAddress = signedOrder.makerAddress;
|
||||
let isPreSigned = await contractWrappers.exchange.preSigned.callAsync(hash, signerAddress);
|
||||
expect(isPreSigned).to.be.false();
|
||||
await contractWrappers.exchange.preSign.awaitTransactionSuccessAsync(
|
||||
hash,
|
||||
signerAddress,
|
||||
signedOrder.signature,
|
||||
{ from: senderAddress },
|
||||
);
|
||||
isPreSigned = await contractWrappers.exchange.preSigned.callAsync(hash, signerAddress);
|
||||
expect(isPreSigned).to.be.true();
|
||||
|
||||
const preSignedSignature = '0x06';
|
||||
const isValidSignature = await contractWrappers.exchange.isValidSignature.callAsync(
|
||||
hash,
|
||||
signerAddress,
|
||||
preSignedSignature,
|
||||
);
|
||||
expect(isValidSignature).to.be.true();
|
||||
|
||||
// Test our TS implementation of signature validation
|
||||
const isValidSignatureInTs = await signatureUtils.isValidSignatureAsync(
|
||||
provider,
|
||||
hash,
|
||||
preSignedSignature,
|
||||
signerAddress,
|
||||
);
|
||||
expect(isValidSignatureInTs).to.be.true();
|
||||
});
|
||||
});
|
||||
describe('#getVersionAsync', () => {
|
||||
it('should return version the hash', async () => {
|
||||
const version = await contractWrappers.exchange.VERSION.callAsync();
|
||||
const VERSION = '2.0.0';
|
||||
expect(version).to.be.equal(VERSION);
|
||||
});
|
||||
});
|
||||
describe('#subscribe', () => {
|
||||
const indexFilterValues = {};
|
||||
const takerTokenFillAmountInBaseUnits = new BigNumber(1);
|
||||
beforeEach(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerAssetData,
|
||||
takerAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
afterEach(async () => {
|
||||
contractWrappers.exchange.unsubscribeAll();
|
||||
});
|
||||
// Hack: Mocha does not allow a test to be both async and have a `done` callback
|
||||
// Since we need to await the receipt of the event in the `subscribe` callback,
|
||||
// we do need both. A hack is to make the top-level a sync fn w/ a done callback and then
|
||||
// wrap the rest of the test in an async block
|
||||
// Source: https://github.com/mochajs/mocha/issues/2407
|
||||
it('Should receive the Fill event when an order is filled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => {
|
||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.Fill);
|
||||
},
|
||||
);
|
||||
contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callback);
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmountInBaseUnits,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ExchangeCancelEventArgs>) => {
|
||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.Cancel);
|
||||
},
|
||||
);
|
||||
contractWrappers.exchange.subscribe(ExchangeEvents.Cancel, indexFilterValues, callback);
|
||||
await contractWrappers.exchange.cancelOrder.awaitTransactionSuccessAsync(signedOrder, {
|
||||
from: makerAddress,
|
||||
});
|
||||
})().catch(done);
|
||||
});
|
||||
it('Outstanding subscriptions are cancelled when contractWrappers.unsubscribeAll called', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
},
|
||||
);
|
||||
contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callbackNeverToBeCalled);
|
||||
|
||||
contractWrappers.unsubscribeAll();
|
||||
|
||||
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => {
|
||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.Fill);
|
||||
},
|
||||
);
|
||||
contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callback);
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmountInBaseUnits,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(
|
||||
(_logEvent: DecodedLogEvent<ExchangeFillEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
},
|
||||
);
|
||||
const subscriptionToken = contractWrappers.exchange.subscribe(
|
||||
ExchangeEvents.Fill,
|
||||
indexFilterValues,
|
||||
callbackNeverToBeCalled,
|
||||
);
|
||||
contractWrappers.exchange.unsubscribe(subscriptionToken);
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmountInBaseUnits,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
done();
|
||||
})().catch(done);
|
||||
});
|
||||
});
|
||||
describe('#getLogsAsync', () => {
|
||||
const blockRange = {
|
||||
fromBlock: 0,
|
||||
toBlock: BlockParamLiteral.Latest,
|
||||
};
|
||||
it('should get logs with decoded args emitted by Fill', async () => {
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
const eventName = ExchangeEvents.Fill;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.exchange.getLogsAsync(eventName, blockRange, indexFilterValues);
|
||||
expect(logs).to.have.length(1);
|
||||
expect(logs[0].event).to.be.equal(eventName);
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
const differentEventName = ExchangeEvents.Cancel;
|
||||
const indexFilterValues = {};
|
||||
const logs = await contractWrappers.exchange.getLogsAsync(
|
||||
differentEventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(0);
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
const signedOrderWithAnotherMakerAddress = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerAssetData,
|
||||
takerAssetData,
|
||||
anotherMakerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
signedOrderWithAnotherMakerAddress,
|
||||
takerTokenFillAmount,
|
||||
signedOrderWithAnotherMakerAddress.signature,
|
||||
{ from: takerAddress },
|
||||
);
|
||||
const eventName = ExchangeEvents.Fill;
|
||||
const indexFilterValues = {
|
||||
makerAddress: anotherMakerAddress,
|
||||
};
|
||||
const logs = await contractWrappers.exchange.getLogsAsync<ExchangeFillEventArgs>(
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
expect(args.makerAddress).to.be.equal(anotherMakerAddress);
|
||||
});
|
||||
});
|
||||
}); // tslint:disable:max-file-line-count
|
||||
Reference in New Issue
Block a user