Readability improvements

This commit is contained in:
Greg Hysen 2019-08-13 22:34:53 +02:00
parent dd4541c825
commit 09b5018e65
5 changed files with 61 additions and 101 deletions

View File

@ -1,9 +1,15 @@
import { artifacts as proxyArtifacts , ERC1155ProxyWrapper, ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy'; import {
artifacts as proxyArtifacts,
ERC1155ProxyWrapper,
ERC20Wrapper,
ERC721Wrapper,
} from '@0x/contracts-asset-proxy';
import { artifacts as erc20Artifacts } from '@0x/contracts-erc20'; import { artifacts as erc20Artifacts } from '@0x/contracts-erc20';
import { artifacts as erc721Artifacts } from '@0x/contracts-erc721'; import { artifacts as erc721Artifacts } from '@0x/contracts-erc721';
import { import {
chaiSetup, expect,
FillEventArgs, FillEventArgs,
filterLogsToArguments,
LogDecoder, LogDecoder,
OrderStatus, OrderStatus,
orderUtils, orderUtils,
@ -13,22 +19,20 @@ import { orderHashUtils } from '@0x/order-utils';
import { FillResults, SignedOrder } from '@0x/types'; import { FillResults, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper'; import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai'; import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { artifacts, ExchangeContract } from '../../src'; import { artifacts, ExchangeContract } from '../../src';
import { calculateFillResults } from '../../src/reference_functions';
import { BalanceStore } from '../balance_stores/balance_store'; import { BalanceStore } from '../balance_stores/balance_store';
import { BlockchainBalanceStore } from '../balance_stores/blockchain_balance_store'; import { BlockchainBalanceStore } from '../balance_stores/blockchain_balance_store';
import { LocalBalanceStore } from '../balance_stores/local_balance_store'; import { LocalBalanceStore } from '../balance_stores/local_balance_store';
chaiSetup.configure();
const expect = chai.expect;
export class FillOrderWrapper { export class FillOrderWrapper {
private readonly _exchange: ExchangeContract; private readonly _exchange: ExchangeContract;
private readonly _blockchainBalanceStore: BlockchainBalanceStore; private readonly _blockchainBalanceStore: BlockchainBalanceStore;
private readonly _web3Wrapper: Web3Wrapper; private readonly _web3Wrapper: Web3Wrapper;
/** /**
* Simulates matching two orders by transferring amounts defined in * Simulates matching two orders by transferring amounts defined in
* `transferAmounts` and returns the results. * `transferAmounts` and returns the results.
@ -43,16 +47,11 @@ export class FillOrderWrapper {
takerAddress: string, takerAddress: string,
opts: { takerAssetFillAmount?: BigNumber } = {}, opts: { takerAssetFillAmount?: BigNumber } = {},
initBalanceStore: BalanceStore, initBalanceStore: BalanceStore,
partialFillResults: Partial<FillResults>,
): [FillResults, FillEventArgs, BalanceStore] { ): [FillResults, FillEventArgs, BalanceStore] {
const balanceStore = LocalBalanceStore.create(initBalanceStore); const balanceStore = LocalBalanceStore.create(initBalanceStore);
const takerAssetFillAmount = const takerAssetFillAmount =
opts.takerAssetFillAmount !== undefined ? opts.takerAssetFillAmount : signedOrder.takerAssetAmount; opts.takerAssetFillAmount !== undefined ? opts.takerAssetFillAmount : signedOrder.takerAssetAmount;
const fillResults = FillOrderWrapper._createFillResultsFromPartial( const fillResults = calculateFillResults(signedOrder, takerAssetFillAmount);
partialFillResults,
signedOrder,
takerAssetFillAmount,
);
const fillEvent = FillOrderWrapper.simulateFillEvent(signedOrder, takerAddress, fillResults); const fillEvent = FillOrderWrapper.simulateFillEvent(signedOrder, takerAddress, fillResults);
// Taker -> Maker // Taker -> Maker
balanceStore.transferAsset( balanceStore.transferAsset(
@ -61,13 +60,6 @@ export class FillOrderWrapper {
fillResults.takerAssetFilledAmount, fillResults.takerAssetFilledAmount,
signedOrder.takerAssetData, signedOrder.takerAssetData,
); );
// Taker -> Fee Recipient
balanceStore.transferAsset(
takerAddress,
signedOrder.feeRecipientAddress,
fillResults.takerFeePaid,
signedOrder.takerFeeAssetData,
);
// Maker -> Taker // Maker -> Taker
balanceStore.transferAsset( balanceStore.transferAsset(
signedOrder.makerAddress, signedOrder.makerAddress,
@ -75,6 +67,13 @@ export class FillOrderWrapper {
fillResults.makerAssetFilledAmount, fillResults.makerAssetFilledAmount,
signedOrder.makerAssetData, signedOrder.makerAssetData,
); );
// Taker -> Fee Recipient
balanceStore.transferAsset(
takerAddress,
signedOrder.feeRecipientAddress,
fillResults.takerFeePaid,
signedOrder.takerFeeAssetData,
);
// Maker -> Fee Recipient // Maker -> Fee Recipient
balanceStore.transferAsset( balanceStore.transferAsset(
signedOrder.makerAddress, signedOrder.makerAddress,
@ -84,6 +83,7 @@ export class FillOrderWrapper {
); );
return [fillResults, fillEvent, balanceStore]; return [fillResults, fillEvent, balanceStore];
} }
/** /**
* Simulates the event emitted by the exchange contract when an order is filled. * Simulates the event emitted by the exchange contract when an order is filled.
*/ */
@ -99,61 +99,24 @@ export class FillOrderWrapper {
takerFeePaid: fillResults.takerFeePaid, takerFeePaid: fillResults.takerFeePaid,
}; };
} }
/** /**
* Extract the exchanges `Fill` event from a transaction receipt. * Extract the exchanges `Fill` event from a transaction receipt.
*/ */
public static _extractFillEventsfromReceipt(receipt: TransactionReceiptWithDecodedLogs): FillEventArgs[] { private static _extractFillEventsfromReceipt(receipt: TransactionReceiptWithDecodedLogs): FillEventArgs[] {
interface RawFillEventArgs { const events = filterLogsToArguments<FillEventArgs>(receipt.logs, 'Fill');
orderHash: string; const fieldsOfInterest = [
makerAddress: string; 'orderHash',
takerAddress: string; 'makerAddress',
makerAssetFilledAmount: string; 'takerAddress',
takerAssetFilledAmount: string; 'makerAssetFilledAmount',
makerFeePaid: string; 'takerAssetFilledAmount',
takerFeePaid: string; 'makerFeePaid',
} 'takerFeePaid',
const actualFills = (_.filter(receipt.logs, ['event', 'Fill']) as any) as Array< ];
LogWithDecodedArgs<RawFillEventArgs> return events.map(event => _.pick(event, fieldsOfInterest)) as FillEventArgs[];
>;
// Convert RawFillEventArgs to FillEventArgs.
return actualFills.map(fill => ({
orderHash: fill.args.orderHash,
makerAddress: fill.args.makerAddress,
takerAddress: fill.args.takerAddress,
makerAssetFilledAmount: new BigNumber(fill.args.makerAssetFilledAmount),
takerAssetFilledAmount: new BigNumber(fill.args.takerAssetFilledAmount),
makerFeePaid: new BigNumber(fill.args.makerFeePaid),
takerFeePaid: new BigNumber(fill.args.takerFeePaid),
}));
}
/**
* Returns a completed `FillResults` given a partial instance. The correct values are inferred by the
* values in the `signedOrder` and `takerAssetFillAmount`.
*/
private static _createFillResultsFromPartial(
partialFillResults: Partial<FillResults>,
signedOrder: SignedOrder,
takerAssetFillAmount: BigNumber,
): FillResults {
return {
makerAssetFilledAmount:
partialFillResults.makerAssetFilledAmount !== undefined
? partialFillResults.makerAssetFilledAmount
: signedOrder.makerAssetAmount.times(takerAssetFillAmount).dividedBy(signedOrder.takerAssetAmount),
takerAssetFilledAmount:
partialFillResults.takerAssetFilledAmount !== undefined
? partialFillResults.takerAssetFilledAmount
: signedOrder.takerAssetAmount.times(takerAssetFillAmount).dividedBy(signedOrder.takerAssetAmount),
makerFeePaid:
partialFillResults.makerFeePaid !== undefined
? partialFillResults.makerFeePaid
: signedOrder.makerFee.times(takerAssetFillAmount).dividedBy(signedOrder.takerAssetAmount),
takerFeePaid:
partialFillResults.takerFeePaid !== undefined
? partialFillResults.takerFeePaid
: signedOrder.takerFee.times(takerAssetFillAmount).dividedBy(signedOrder.takerAssetAmount),
};
} }
/** /**
* Constructor. * Constructor.
* @param exchangeContract Insstance of the deployed exchange contract * @param exchangeContract Insstance of the deployed exchange contract
@ -173,12 +136,14 @@ export class FillOrderWrapper {
this._blockchainBalanceStore = new BlockchainBalanceStore(erc20Wrapper, erc721Wrapper, erc1155ProxyWrapper); this._blockchainBalanceStore = new BlockchainBalanceStore(erc20Wrapper, erc721Wrapper, erc1155ProxyWrapper);
this._web3Wrapper = new Web3Wrapper(provider); this._web3Wrapper = new Web3Wrapper(provider);
} }
/** /**
* Returns the balance store used by this wrapper. * Returns the balance store used by this wrapper.
*/ */
public getBlockchainBalanceStore(): BlockchainBalanceStore { public getBlockchainBalanceStore(): BlockchainBalanceStore {
return this._blockchainBalanceStore; return this._blockchainBalanceStore;
} }
/** /**
* Fills an order and asserts the effects. This includes * Fills an order and asserts the effects. This includes
* 1. The order info (via `getOrderInfo`) * 1. The order info (via `getOrderInfo`)
@ -190,7 +155,6 @@ export class FillOrderWrapper {
signedOrder: SignedOrder, signedOrder: SignedOrder,
from: string, from: string,
opts: { takerAssetFillAmount?: BigNumber } = {}, opts: { takerAssetFillAmount?: BigNumber } = {},
expectedFillResults: Partial<FillResults> = {},
): Promise<void> { ): Promise<void> {
// Get init state // Get init state
await this._blockchainBalanceStore.updateBalancesAsync(); await this._blockchainBalanceStore.updateBalancesAsync();
@ -204,13 +168,7 @@ export class FillOrderWrapper {
simulatedFillResults, simulatedFillResults,
simulatedFillEvent, simulatedFillEvent,
simulatedFinalBalanceStore, simulatedFinalBalanceStore,
] = FillOrderWrapper.simulateFillOrder( ] = FillOrderWrapper.simulateFillOrder(signedOrder, from, opts, this._blockchainBalanceStore);
signedOrder,
from,
opts,
this._blockchainBalanceStore,
expectedFillResults,
);
const [fillResults, fillEvent] = await this._fillOrderAsync(signedOrder, from, opts); const [fillResults, fillEvent] = await this._fillOrderAsync(signedOrder, from, opts);
// Assert state transition // Assert state transition
expect(simulatedFillResults, 'Fill Results').to.be.deep.equal(fillResults); expect(simulatedFillResults, 'Fill Results').to.be.deep.equal(fillResults);
@ -221,6 +179,7 @@ export class FillOrderWrapper {
const finalTakerAssetFilledAmount = initTakerAssetFilledAmount.plus(fillResults.takerAssetFilledAmount); const finalTakerAssetFilledAmount = initTakerAssetFilledAmount.plus(fillResults.takerAssetFilledAmount);
await this._assertOrderStateAsync(signedOrder, finalTakerAssetFilledAmount); await this._assertOrderStateAsync(signedOrder, finalTakerAssetFilledAmount);
} }
/** /**
* Fills an order on-chain. As an optimization this function auto-updates the blockchain balance store * Fills an order on-chain. As an optimization this function auto-updates the blockchain balance store
* used by this contract. * used by this contract.
@ -255,6 +214,7 @@ export class FillOrderWrapper {
await this._blockchainBalanceStore.updateBalancesAsync(); await this._blockchainBalanceStore.updateBalancesAsync();
return [fillResults, fillEvent]; return [fillResults, fillEvent];
} }
/** /**
* Asserts that the provided order's fill amount and order status * Asserts that the provided order's fill amount and order status
* are the expected values. * are the expected values.

View File

@ -2,8 +2,15 @@ import { ERC1155Holdings, ERC1155HoldingsByOwner, TokenBalances } from '@0x/cont
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
/**
* Note - this should live in `@0x/contracts-test-utils` but that would create a circular
* dependency in `BlockchainBlanceStore`. We should be able to mvoe this once we can rely
* solely on auto-generated wrappers opposed to the existing ERC20Wrapper, ERC721Wrapper,
* and ERC1155Wrapper.
*/
export class BalanceStore { export class BalanceStore {
protected _balances: TokenBalances; protected _balances: TokenBalances;
/** /**
* Returns true iff balance stores do have the same entries. * Returns true iff balance stores do have the same entries.
* @param lhs First balance store to compare * @param lhs First balance store to compare
@ -12,6 +19,7 @@ export class BalanceStore {
public static isEqual(lhs: BalanceStore, rhs: BalanceStore): boolean { public static isEqual(lhs: BalanceStore, rhs: BalanceStore): boolean {
return _.isEqual(lhs.getRawBalances(), rhs.getRawBalances()); return _.isEqual(lhs.getRawBalances(), rhs.getRawBalances());
} }
/** /**
* Throws iff balance stores do not have the same entries. * Throws iff balance stores do not have the same entries.
* @param lhs First balance store to compare * @param lhs First balance store to compare
@ -22,6 +30,7 @@ export class BalanceStore {
throw new Error(`Balance stores are not equal:\n\nLeft:\n${lhs}\n\nRight:\n${rhs}`); throw new Error(`Balance stores are not equal:\n\nLeft:\n${lhs}\n\nRight:\n${rhs}`);
} }
} }
/** /**
* Restructures `ERC1155HoldingsByOwner` to be compatible with `TokenBalances.erc1155`. * Restructures `ERC1155HoldingsByOwner` to be compatible with `TokenBalances.erc1155`.
* @param erc1155HoldingsByOwner Holdings returned by `ERC1155ProxyWrapper.getBalancesAsync()`. * @param erc1155HoldingsByOwner Holdings returned by `ERC1155ProxyWrapper.getBalancesAsync()`.
@ -41,6 +50,7 @@ export class BalanceStore {
} }
return result; return result;
} }
/** /**
* Encodes token balances in a way that they can be compared by lodash. * Encodes token balances in a way that they can be compared by lodash.
*/ */
@ -57,12 +67,14 @@ export class BalanceStore {
const keys = _.keys(obj).sort(); const keys = _.keys(obj).sort();
return _.zip(keys, keys.map(k => BalanceStore._encodeTokenBalances(obj[k]))); return _.zip(keys, keys.map(k => BalanceStore._encodeTokenBalances(obj[k])));
} }
/** /**
* Constructor. * Constructor.
*/ */
public constructor() { public constructor() {
this._balances = { erc20: {}, erc721: {}, erc1155: {} }; this._balances = { erc20: {}, erc721: {}, erc1155: {} };
} }
/** /**
* Copies the balance from an existing balance store. * Copies the balance from an existing balance store.
* @param balanceStore to copy balances from. * @param balanceStore to copy balances from.
@ -70,6 +82,7 @@ export class BalanceStore {
public copyBalancesFrom(balanceStore: BalanceStore): void { public copyBalancesFrom(balanceStore: BalanceStore): void {
this._balances = _.cloneDeep(balanceStore._balances); this._balances = _.cloneDeep(balanceStore._balances);
} }
/** /**
* Returns the raw `TokenBalances` that this class encapsulates. * Returns the raw `TokenBalances` that this class encapsulates.
*/ */

View File

@ -1,5 +1,4 @@
import { ERC1155ProxyWrapper, ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy'; import { ERC1155ProxyWrapper, ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy';
import * as _ from 'lodash';
import { BalanceStore } from './balance_store'; import { BalanceStore } from './balance_store';
@ -7,6 +6,7 @@ export class BlockchainBalanceStore extends BalanceStore {
private readonly _erc20Wrapper: ERC20Wrapper; private readonly _erc20Wrapper: ERC20Wrapper;
private readonly _erc721Wrapper: ERC721Wrapper; private readonly _erc721Wrapper: ERC721Wrapper;
private readonly _erc1155ProxyWrapper: ERC1155ProxyWrapper; private readonly _erc1155ProxyWrapper: ERC1155ProxyWrapper;
/** /**
* Constructor. * Constructor.
* @param erc20Wrapper The ERC20 Wrapper used to interface with deployed erc20 tokens. * @param erc20Wrapper The ERC20 Wrapper used to interface with deployed erc20 tokens.
@ -23,6 +23,7 @@ export class BlockchainBalanceStore extends BalanceStore {
this._erc721Wrapper = erc721Wrapper; this._erc721Wrapper = erc721Wrapper;
this._erc1155ProxyWrapper = erc1155ProxyWrapper; this._erc1155ProxyWrapper = erc1155ProxyWrapper;
} }
/** /**
* Updates balances by querying on-chain values managed by the erc20, erc721, and erc1155 wrappers. * Updates balances by querying on-chain values managed by the erc20, erc721, and erc1155 wrappers.
*/ */

View File

@ -17,12 +17,14 @@ export class LocalBalanceStore extends BalanceStore {
} }
return localBalanceStore; return localBalanceStore;
} }
/** /**
* Constructor. * Constructor.
*/ */
public constructor() { public constructor() {
super(); super();
} }
/** /**
* Transfers assets from `fromAddress` to `toAddress`. * Transfers assets from `fromAddress` to `toAddress`.
* @param fromAddress Sender of asset(s) * @param fromAddress Sender of asset(s)
@ -84,7 +86,7 @@ export class LocalBalanceStore extends BalanceStore {
} }
} }
// sort NFT's by name // sort NFT's by name
toBalances.nonFungible = _.sortBy(toBalances.nonFungible); toBalances.nonFungible.sort();
break; break;
} }
case AssetProxyId.MultiAsset: { case AssetProxyId.MultiAsset: {

View File

@ -17,9 +17,11 @@ import {
} from '@0x/contracts-erc20'; } from '@0x/contracts-erc20';
import { DummyERC721TokenContract } from '@0x/contracts-erc721'; import { DummyERC721TokenContract } from '@0x/contracts-erc721';
import { import {
chaiSetup, blockchainTests,
constants, constants,
describe,
ERC20BalancesByOwner, ERC20BalancesByOwner,
expect,
getLatestBlockTimestampAsync, getLatestBlockTimestampAsync,
hexConcat, hexConcat,
increaseTimeAndMineBlockAsync, increaseTimeAndMineBlockAsync,
@ -29,12 +31,10 @@ import {
txDefaults, txDefaults,
web3Wrapper, web3Wrapper,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils, ExchangeRevertErrors, LibMathRevertErrors, orderHashUtils } from '@0x/order-utils'; import { assetDataUtils, ExchangeRevertErrors, LibMathRevertErrors, orderHashUtils } from '@0x/order-utils';
import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
import { BigNumber, providerUtils, ReentrancyGuardRevertErrors, StringRevertError } from '@0x/utils'; import { BigNumber, providerUtils, ReentrancyGuardRevertErrors, StringRevertError } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper'; import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types'; import { LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash'; import * as _ from 'lodash';
@ -51,14 +51,10 @@ import {
ValidatorWalletDataType, ValidatorWalletDataType,
} from '../src'; } from '../src';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
import { FillOrderWrapper } from './assertion_wrappers/fill_order_wrapper'; import { FillOrderWrapper } from './assertion_wrappers/fill_order_wrapper';
// tslint:disable:no-unnecessary-type-assertion // tslint:disable:no-unnecessary-type-assertion
describe('Exchange core', () => { blockchainTests.resets('Exchange core', () => {
let chainId: number; let chainId: number;
let makerAddress: string; let makerAddress: string;
let owner: string; let owner: string;
@ -102,12 +98,6 @@ describe('Exchange core', () => {
let fillOrderWrapper: FillOrderWrapper; let fillOrderWrapper: FillOrderWrapper;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => { before(async () => {
chainId = await providerUtils.getChainIdAsync(provider); chainId = await providerUtils.getChainIdAsync(provider);
const accounts = await web3Wrapper.getAvailableAddressesAsync(); const accounts = await web3Wrapper.getAvailableAddressesAsync();
@ -240,12 +230,6 @@ describe('Exchange core', () => {
orderFactory = new OrderFactory(privateKey, defaultOrderParams); orderFactory = new OrderFactory(privateKey, defaultOrderParams);
fillOrderWrapper = new FillOrderWrapper(exchange, erc20Wrapper, erc721Wrapper, erc1155ProxyWrapper, provider); fillOrderWrapper = new FillOrderWrapper(exchange, erc20Wrapper, erc721Wrapper, erc1155ProxyWrapper, provider);
}); });
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('fillOrder', () => { describe('fillOrder', () => {
beforeEach(async () => { beforeEach(async () => {
erc20Balances = await erc20Wrapper.getBalancesAsync(); erc20Balances = await erc20Wrapper.getBalancesAsync();