Refactor ExchangeTransferSimulator public interface to accet an AbstractBalanceAndProxyAllowanceLazyStore so that this module could be re-used in different contexts.

This commit is contained in:
Fabio Berger
2018-06-11 10:24:55 +02:00
parent 817c332d11
commit ce6078ed94
6 changed files with 71 additions and 19 deletions

View File

@@ -0,0 +1,11 @@
import { BigNumber } from '@0xproject/utils';
export abstract class AbstractBalanceAndProxyAllowanceLazyStore {
public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber>;
public abstract setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void;
public abstract deleteBalance(tokenAddress: string, userAddress: string): void;
public abstract setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void;
public abstract deleteProxyAllowance(tokenAddress: string, userAddress: string): void;
public abstract deleteAll(): void;
}

View File

@@ -18,6 +18,7 @@ import * as _ from 'lodash';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher'; import { SimpleBalanceAndProxyAllowanceFetcher } from '../fetchers/simple_balance_and_proxy_allowance_fetcher';
import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher'; import { SimpleOrderFilledCancelledFetcher } from '../fetchers/simple_order_filled_cancelled_fetcher';
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
import { import {
BlockRange, BlockRange,
EventCallback, EventCallback,
@@ -177,7 +178,11 @@ export class ExchangeWrapper extends ContractWrapper {
: orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
@@ -252,7 +257,11 @@ export class ExchangeWrapper extends ContractWrapper {
if (shouldValidate) { if (shouldValidate) {
let filledTakerTokenAmount = new BigNumber(0); let filledTakerTokenAmount = new BigNumber(0);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
for (const signedOrder of signedOrders) { for (const signedOrder of signedOrders) {
const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
@@ -345,7 +354,11 @@ export class ExchangeWrapper extends ContractWrapper {
: orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
for (const orderFillRequest of orderFillRequests) { for (const orderFillRequest of orderFillRequests) {
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
@@ -421,7 +434,11 @@ export class ExchangeWrapper extends ContractWrapper {
: orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
@@ -483,7 +500,11 @@ export class ExchangeWrapper extends ContractWrapper {
: orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
for (const orderFillRequest of orderFillRequests) { for (const orderFillRequest of orderFillRequests) {
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
@@ -733,7 +754,11 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined; const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
await this._orderValidationUtils.validateOrderFillableOrThrowAsync( await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
@@ -759,7 +784,11 @@ export class ExchangeWrapper extends ContractWrapper {
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const normalizedTakerAddress = takerAddress.toLowerCase(); const normalizedTakerAddress = takerAddress.toLowerCase();
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
@@ -806,7 +835,11 @@ export class ExchangeWrapper extends ContractWrapper {
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const normalizedTakerAddress = takerAddress.toLowerCase(); const normalizedTakerAddress = takerAddress.toLowerCase();
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
this._tokenWrapper,
BlockParamLiteral.Latest,
);
const exchangeTradeEmulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync( await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,

View File

@@ -1,14 +1,14 @@
import { AbstractBalanceAndProxyAllowanceFetcher } from '@0xproject/order-utils';
import { BlockParamLiteral } from '@0xproject/types'; import { BlockParamLiteral } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
import { TokenWrapper } from '../contract_wrappers/token_wrapper'; import { TokenWrapper } from '../contract_wrappers/token_wrapper';
/** /**
* Copy on read store for balances/proxyAllowances of tokens/accounts * Copy on read store for balances/proxyAllowances of tokens/accounts
*/ */
export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceFetcher { export class BalanceAndProxyAllowanceLazyStore implements AbstractBalanceAndProxyAllowanceLazyStore {
private _tokenWrapper: TokenWrapper; private _tokenWrapper: TokenWrapper;
private _defaultBlock: BlockParamLiteral; private _defaultBlock: BlockParamLiteral;
private _balance: { private _balance: {

View File

@@ -1,8 +1,8 @@
import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types'; import { BlockParamLiteral, ExchangeContractErrs } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import { AbstractBalanceAndProxyAllowanceLazyStore } from '../abstract/abstract_balance_and_proxy_allowance_lazy_store';
import { TokenWrapper } from '../contract_wrappers/token_wrapper'; import { TokenWrapper } from '../contract_wrappers/token_wrapper';
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
import { TradeSide, TransferType } from '../types'; import { TradeSide, TransferType } from '../types';
import { constants } from '../utils/constants'; import { constants } from '../utils/constants';
@@ -35,8 +35,7 @@ const ERR_MSG_MAPPING = {
}; };
export class ExchangeTransferSimulator { export class ExchangeTransferSimulator {
private _store: BalanceAndProxyAllowanceLazyStore; private _store: AbstractBalanceAndProxyAllowanceLazyStore;
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
private static _throwValidationError( private static _throwValidationError(
failureReason: FailureReason, failureReason: FailureReason,
tradeSide: TradeSide, tradeSide: TradeSide,
@@ -45,9 +44,8 @@ export class ExchangeTransferSimulator {
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType]; const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
throw new Error(errMsg); throw new Error(errMsg);
} }
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) { constructor(store: AbstractBalanceAndProxyAllowanceLazyStore) {
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock); this._store = store;
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
} }
/** /**
* Simulates transferFrom call performed by a proxy * Simulates transferFrom call performed by a proxy
@@ -91,7 +89,7 @@ export class ExchangeTransferSimulator {
amountInBaseUnits: BigNumber, amountInBaseUnits: BigNumber,
): Promise<void> { ): Promise<void> {
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress); const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) { if (!proxyAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits)); this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
} }
} }

View File

@@ -5,6 +5,7 @@ import * as chai from 'chai';
import 'make-promises-safe'; import 'make-promises-safe';
import { ContractWrappers, ExchangeContractErrs } from '../src'; import { ContractWrappers, ExchangeContractErrs } from '../src';
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
import { TradeSide, TransferType } from '../src/types'; import { TradeSide, TransferType } from '../src/types';
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
@@ -44,7 +45,11 @@ describe('ExchangeTransferSimulator', () => {
}); });
describe('#transferFromAsync', () => { describe('#transferFromAsync', () => {
beforeEach(() => { beforeEach(() => {
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
contractWrappers.token,
BlockParamLiteral.Latest,
);
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
}); });
it("throws if the user doesn't have enough allowance", async () => { it("throws if the user doesn't have enough allowance", async () => {
return expect( return expect(

View File

@@ -8,6 +8,7 @@ import 'make-promises-safe';
import * as Sinon from 'sinon'; import * as Sinon from 'sinon';
import { ContractWrappers, ExchangeContractErrs, SignedOrder, Token } from '../src'; import { ContractWrappers, ExchangeContractErrs, SignedOrder, Token } from '../src';
import { BalanceAndProxyAllowanceLazyStore } from '../src/stores/balance_proxy_allowance_lazy_store';
import { TradeSide, TransferType } from '../src/types'; import { TradeSide, TransferType } from '../src/types';
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator'; import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
import { OrderValidationUtils } from '../src/utils/order_validation_utils'; import { OrderValidationUtils } from '../src/utils/order_validation_utils';
@@ -332,7 +333,11 @@ describe('OrderValidation', () => {
return Sinon.match((value: BigNumber) => value.eq(expected)); return Sinon.match((value: BigNumber) => value.eq(expected));
}; };
beforeEach('create exchangeTransferSimulator', async () => { beforeEach('create exchangeTransferSimulator', async () => {
exchangeTransferSimulator = new ExchangeTransferSimulator(contractWrappers.token, BlockParamLiteral.Latest); const balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
contractWrappers.token,
BlockParamLiteral.Latest,
);
exchangeTransferSimulator = new ExchangeTransferSimulator(balanceAndProxyAllowanceLazyStore);
transferFromAsync = Sinon.spy(); transferFromAsync = Sinon.spy();
exchangeTransferSimulator.transferFromAsync = transferFromAsync as any; exchangeTransferSimulator.transferFromAsync = transferFromAsync as any;
}); });