@0x/contracts-exchange
: Create IsolatedExchangeWrapper
class.
This commit is contained in:
parent
0851c5ac8e
commit
1030c96eec
@ -49,7 +49,7 @@ contract TestIsolatedExchange is
|
||||
|
||||
/// @dev Convenience function to get the `rawAssetBalances` for
|
||||
/// multiple addresses.
|
||||
function getMultipleRawAssetBalanceChanges(
|
||||
function getRawAssetBalances(
|
||||
bytes calldata assetData,
|
||||
address[] calldata addresses
|
||||
)
|
||||
|
@ -1,30 +1,14 @@
|
||||
import {
|
||||
addressUtils,
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
FillResults,
|
||||
LogDecoder,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { Order } from '@0x/types';
|
||||
import { blockchainTests, constants, expect, hexRandom } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
TestIsolatedExchangeContract,
|
||||
TestIsolatedExchangeDispatchTransferFromCalledEventArgs as DispatchTransferFromCallArgs,
|
||||
TestIsolatedExchangeFillEventArgs as FillEventArgs,
|
||||
} from '../src';
|
||||
import { IsolatedExchangeWrapper, Order } from './utils/isolated_exchange_wrapper';
|
||||
|
||||
blockchainTests.resets.only('Isolated fillOrder() tests', env => {
|
||||
const GOOD_SIGNATURE = '0x0101';
|
||||
const BAD_SIGNATURE = '0x0001';
|
||||
const TOMORROW = Math.floor(_.now() / 1000) + 60 * 60 * 24;
|
||||
const DEFAULT_ORDER: Order = {
|
||||
senderAddress: constants.NULL_ADDRESS,
|
||||
makerAddress: addressUtils.generatePseudoRandomAddress(),
|
||||
makerAddress: randomAddress(),
|
||||
takerAddress: constants.NULL_ADDRESS,
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
takerFee: constants.ZERO_AMOUNT,
|
||||
@ -37,96 +21,21 @@ blockchainTests.resets.only('Isolated fillOrder() tests', env => {
|
||||
salt: constants.ZERO_AMOUNT,
|
||||
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||
expirationTimeSeconds: toBN(TOMORROW),
|
||||
domain: {
|
||||
verifyingContractAddress: constants.NULL_ADDRESS,
|
||||
chainId: 1337,
|
||||
},
|
||||
};
|
||||
let takerAddress: string;
|
||||
let testExchange: TestIsolatedExchangeContract;
|
||||
let logDecoder: LogDecoder;
|
||||
let testExchange: IsolatedExchangeWrapper;
|
||||
let nextSaltValue = 1;
|
||||
|
||||
before(async () => {
|
||||
[ takerAddress ] = await env.getAccountAddressesAsync();
|
||||
testExchange = await TestIsolatedExchangeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestIsolatedExchange,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
[takerAddress] = await env.getAccountAddressesAsync();
|
||||
testExchange = await IsolatedExchangeWrapper.deployAsync(
|
||||
env.web3Wrapper,
|
||||
_.assign(env.txDefaults, { from: takerAddress }),
|
||||
);
|
||||
logDecoder = new LogDecoder(env.web3Wrapper, artifacts);
|
||||
});
|
||||
|
||||
interface IsolatedExchangeAssetBalances {
|
||||
[assetData: string]: {[address: string]: BigNumber};
|
||||
}
|
||||
|
||||
interface IsolatedFillOrderAsyncResults {
|
||||
fillResults: FillResults;
|
||||
fillEventArgs: FillEventArgs;
|
||||
transferFromCalls: DispatchTransferFromCallArgs[];
|
||||
balances: IsolatedExchangeAssetBalances;
|
||||
}
|
||||
|
||||
async function isolatedFillOrderAsync(
|
||||
order: Order,
|
||||
takerAssetFillAmount: BigNumber | number,
|
||||
signature: string = GOOD_SIGNATURE,
|
||||
): Promise<IsolatedFillOrderAsyncResults> {
|
||||
const _takerAssetFillAmount = toBN(takerAssetFillAmount);
|
||||
// Call to get the return value.
|
||||
const fillResults = await testExchange.fillOrder.callAsync(
|
||||
order,
|
||||
_takerAssetFillAmount,
|
||||
signature,
|
||||
);
|
||||
// Transact to execute it.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await testExchange.fillOrder.sendTransactionAsync(
|
||||
order,
|
||||
_takerAssetFillAmount,
|
||||
signature,
|
||||
),
|
||||
);
|
||||
// Parse logs.
|
||||
const fillEventArgs = (receipt.logs[0] as LogWithDecodedArgs<FillEventArgs>).args;
|
||||
const transferFromCalls =
|
||||
(receipt.logs.slice(1) as Array<LogWithDecodedArgs<DispatchTransferFromCallArgs>>).map(
|
||||
log => log.args,
|
||||
);
|
||||
// Extract addresses involved in transfers.
|
||||
const addresses = _.uniq(_.flatten(transferFromCalls.map(c => [c.from, c.to])));
|
||||
// Extract assets involved in transfers.
|
||||
const assets = _.uniq(transferFromCalls.map(c => c.assetData));
|
||||
// Query balances of addresses and assets involved in transfers.
|
||||
const balances = await (async () => {
|
||||
const result: IsolatedExchangeAssetBalances = {};
|
||||
for (const assetData of assets) {
|
||||
result[assetData] = _.zipObject(
|
||||
addresses,
|
||||
await testExchange.getMultipleRawAssetBalanceChanges.callAsync(
|
||||
assetData,
|
||||
addresses,
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
return {
|
||||
fillResults,
|
||||
fillEventArgs,
|
||||
transferFromCalls,
|
||||
balances,
|
||||
};
|
||||
}
|
||||
|
||||
function createOrder(details: Partial<Order> = {}): Order {
|
||||
return _.assign(
|
||||
{},
|
||||
DEFAULT_ORDER,
|
||||
{ salt: toBN(nextSaltValue++) },
|
||||
details,
|
||||
);
|
||||
return _.assign({}, DEFAULT_ORDER, { salt: toBN(nextSaltValue++) }, details);
|
||||
}
|
||||
|
||||
it('works', async () => {
|
||||
@ -134,11 +43,15 @@ blockchainTests.resets.only('Isolated fillOrder() tests', env => {
|
||||
makerAssetAmount: toBN(1),
|
||||
takerAssetAmount: toBN(2),
|
||||
});
|
||||
const results = await isolatedFillOrderAsync(order, 2);
|
||||
console.log(results);
|
||||
const results = await testExchange.fillOrderAsync(order, 2);
|
||||
console.log(results, testExchange.getOrderHash(order));
|
||||
});
|
||||
});
|
||||
|
||||
function toBN(num: BigNumber | string | number): BigNumber {
|
||||
return new BigNumber(num);
|
||||
}
|
||||
|
||||
function randomAddress(): string {
|
||||
return hexRandom(constants.ADDRESS_LENGTH);
|
||||
}
|
||||
|
129
contracts/exchange/test/utils/isolated_exchange_wrapper.ts
Normal file
129
contracts/exchange/test/utils/isolated_exchange_wrapper.ts
Normal file
@ -0,0 +1,129 @@
|
||||
import { FillResults, filterLogsToArguments, LogDecoder, txDefaults as testTxDefaults } from '@0x/contracts-test-utils';
|
||||
import { orderHashUtils } from '@0x/order-utils';
|
||||
import { OrderWithoutDomain, SignatureType } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { TxData, Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
TestIsolatedExchangeContract,
|
||||
TestIsolatedExchangeDispatchTransferFromCalledEventArgs as DispatchTransferFromCallArgs,
|
||||
TestIsolatedExchangeFillEventArgs as FillEventArgs,
|
||||
} from '../../src';
|
||||
|
||||
/**
|
||||
* @dev Create a signature for the `TestIsolatedExchange` contract that will pass.
|
||||
*/
|
||||
export function createGoodSignature(type: SignatureType = SignatureType.EIP712): string {
|
||||
return `0x01${Buffer.from([type]).toString('hex')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Create a signature for the `TestIsolatedExchange` contract that will fail.
|
||||
*/
|
||||
export function createBadSignature(type: SignatureType = SignatureType.EIP712): string {
|
||||
return `0x00${Buffer.from([type]).toString('hex')}`;
|
||||
}
|
||||
|
||||
export interface IsolatedAssetBalances {
|
||||
[assetData: string]: { [address: string]: BigNumber };
|
||||
}
|
||||
|
||||
export interface IsolatedFillOrderResults {
|
||||
fillResults: FillResults;
|
||||
fillEventArgs: FillEventArgs;
|
||||
transferFromCalls: DispatchTransferFromCallArgs[];
|
||||
balances: IsolatedAssetBalances;
|
||||
}
|
||||
|
||||
export type Order = OrderWithoutDomain;
|
||||
|
||||
export const DEFAULT_GOOD_SIGNATURE = createGoodSignature();
|
||||
export const DEFAULT_BAD_SIGNATURE = createBadSignature();
|
||||
|
||||
/**
|
||||
* @dev Convenience wrapper for the `TestIsolatedExchange` contract.
|
||||
*/
|
||||
export class IsolatedExchangeWrapper {
|
||||
public instance: TestIsolatedExchangeContract;
|
||||
public logDecoder: LogDecoder;
|
||||
|
||||
public static async deployAsync(
|
||||
web3Wrapper: Web3Wrapper,
|
||||
txDefaults: Partial<TxData> = testTxDefaults,
|
||||
): Promise<IsolatedExchangeWrapper> {
|
||||
const provider = web3Wrapper.getProvider();
|
||||
const instance = await TestIsolatedExchangeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestIsolatedExchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
return new IsolatedExchangeWrapper(web3Wrapper, instance);
|
||||
}
|
||||
|
||||
public static fromAddress(
|
||||
address: string,
|
||||
web3Wrapper: Web3Wrapper,
|
||||
txDefaults: Partial<TxData> = testTxDefaults,
|
||||
): IsolatedExchangeWrapper {
|
||||
const provider = web3Wrapper.getProvider();
|
||||
const instance = new TestIsolatedExchangeContract(address, provider, txDefaults);
|
||||
return new IsolatedExchangeWrapper(web3Wrapper, instance);
|
||||
}
|
||||
|
||||
public constructor(web3Wrapper: Web3Wrapper, instance: TestIsolatedExchangeContract) {
|
||||
this.instance = instance;
|
||||
this.logDecoder = new LogDecoder(web3Wrapper, artifacts);
|
||||
}
|
||||
|
||||
public async fillOrderAsync(
|
||||
order: Order,
|
||||
takerAssetFillAmount: BigNumber | number,
|
||||
signature: string = DEFAULT_GOOD_SIGNATURE,
|
||||
txOpts?: TxData,
|
||||
): Promise<IsolatedFillOrderResults> {
|
||||
const _takerAssetFillAmount = new BigNumber(takerAssetFillAmount);
|
||||
// Call to get the return value.
|
||||
const fillResults = await this.instance.fillOrder.callAsync(order, _takerAssetFillAmount, signature, txOpts);
|
||||
// Transact to execute it.
|
||||
const receipt = await this.logDecoder.getTxWithDecodedLogsAsync(
|
||||
await this.instance.fillOrder.sendTransactionAsync(order, _takerAssetFillAmount, signature, txOpts),
|
||||
);
|
||||
// Parse logs.
|
||||
const fillEventArgs = filterLogsToArguments<FillEventArgs>(receipt.logs, 'Fill')[0];
|
||||
const transferFromCalls = filterLogsToArguments<DispatchTransferFromCallArgs>(
|
||||
receipt.logs,
|
||||
'DispatchTransferFromCalled',
|
||||
);
|
||||
// Extract addresses involved in transfers.
|
||||
const addresses = _.uniq(_.flatten(transferFromCalls.map(c => [c.from, c.to])));
|
||||
// Extract assets involved in transfers.
|
||||
const assets = _.uniq(transferFromCalls.map(c => c.assetData));
|
||||
// Query balances of addresses and assets involved in transfers.
|
||||
const balances = await (async () => {
|
||||
const result: IsolatedAssetBalances = {};
|
||||
for (const assetData of assets) {
|
||||
result[assetData] = _.zipObject(
|
||||
addresses,
|
||||
await this.instance.getRawAssetBalances.callAsync(assetData, addresses),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
return {
|
||||
fillResults,
|
||||
fillEventArgs,
|
||||
transferFromCalls,
|
||||
balances,
|
||||
};
|
||||
}
|
||||
|
||||
public getOrderHash(order: Order): string {
|
||||
const domain = {
|
||||
verifyingContractAddress: this.instance.address,
|
||||
chainId: 1337,
|
||||
};
|
||||
return orderHashUtils.getOrderHashHex(_.assign(order, { domain }));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user