@0x/contracts-exchange: Create IsolatedExchangeWrapper class.
				
					
				
			This commit is contained in:
		@@ -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 }));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user