changes for testing

This commit is contained in:
David Sun
2019-07-22 16:33:56 -07:00
parent 4c17c142f9
commit 4b038b07ed
6 changed files with 328 additions and 38 deletions

View File

@@ -75,19 +75,17 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase<SmartContractPar
quote: SwapQuote,
opts: Partial<SwapQuoteGetOutputOpts>,
): Promise<SwapQuoteConsumerBase<SmartContractParams>> {
if (opts.useConsumerType === ConsumerType.Exchange) {
const useConsumerType = opts.useConsumerType || await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync(
quote,
this._contractWrappers,
this.provider,
opts,
);
if (useConsumerType === ConsumerType.Exchange) {
return this._exchangeConsumer;
} else if (opts.useConsumerType === ConsumerType.Forwarder) {
} else if (useConsumerType === ConsumerType.Forwarder) {
return this._forwarderConsumer;
} else {
return swapQuoteConsumerUtils.getConsumerForSwapQuoteAsync(
quote,
this._contractWrappers,
this.provider,
this._exchangeConsumer,
this._forwarderConsumer,
opts,
);
}
return this._exchangeConsumer;
}
}

View File

@@ -9,6 +9,7 @@ import { constants } from '../constants';
import { ExchangeSwapQuoteConsumer } from '../quote_consumers/exchange_swap_quote_consumer';
import { ForwarderSwapQuoteConsumer } from '../quote_consumers/forwarder_swap_quote_consumer';
import {
ConsumerType,
SmartContractParams,
SwapQuote,
SwapQuoteConsumerBase,
@@ -87,10 +88,8 @@ export const swapQuoteConsumerUtils = {
quote: SwapQuote,
contractWrappers: ContractWrappers,
provider: Provider,
exchangeConsumer: ExchangeSwapQuoteConsumer,
forwarderConsumer: ForwarderSwapQuoteConsumer,
opts: Partial<SwapQuoteGetOutputOpts>,
): Promise<SwapQuoteConsumerBase<SmartContractParams>> {
): Promise<ConsumerType> {
const wethAssetData = assetDataUtils.getEtherTokenAssetData(contractWrappers);
if (swapQuoteConsumerUtils.isValidForwarderSwapQuote(quote, wethAssetData)) {
if (opts.takerAddress !== undefined) {
@@ -108,14 +107,14 @@ export const swapQuoteConsumerUtils = {
);
if (isEnoughEthAndWethBalance[1]) {
// should be more gas efficient to use exchange consumer, so if possible use it.
return exchangeConsumer;
return ConsumerType.Exchange;
} else if (isEnoughEthAndWethBalance[0] && !isEnoughEthAndWethBalance[1]) {
return forwarderConsumer;
return ConsumerType.Forwarder;
}
// Note: defaulting to forwarderConsumer if takerAddress is null or not enough balance of either wEth or Eth
return forwarderConsumer;
return ConsumerType.Forwarder;
} else {
return exchangeConsumer;
return ConsumerType.Exchange;
}
},
};

View File

@@ -7,7 +7,7 @@ import { constants } from '../src/constants';
import { affiliateFeeUtils } from '../src/utils/affiliate_fee_utils';
import { chaiSetup } from './utils/chai_setup';
import { getFullyFillableSwapQuoteWithFees, getFullyFillableSwapQuoteWithNoFees, getSignedOrdersWithFees, getSignedOrdersWithNoFees } from './utils/swap_quote';
import { getFullyFillableSwapQuoteWithFees, getFullyFillableSwapQuoteWithNoFees, getPartialSignedOrdersWithFees, getPartialSignedOrdersWithNoFees } from './utils/swap_quote';
chaiSetup.configure();
const expect = chai.expect;
@@ -21,14 +21,14 @@ const FILLABLE_FEE_AMOUNTS = [new BigNumber(1), new BigNumber(1), new BigNumber(
const MARKET_OPERATION = MarketOperation.Sell;
describe('affiliateFeeUtils', () => {
const fakeFeeOrders = getSignedOrdersWithNoFees(
const fakeFeeOrders = getPartialSignedOrdersWithNoFees(
FAKE_MAKER_ASSET_DATA,
FAKE_TAKER_ASSET_DATA,
NULL_ADDRESS,
NULL_ADDRESS,
FILLABLE_FEE_AMOUNTS,
);
const fakeOrders = getSignedOrdersWithNoFees(
const fakeOrders = getPartialSignedOrdersWithNoFees(
FAKE_MAKER_ASSET_DATA,
FAKE_TAKER_ASSET_DATA,
NULL_ADDRESS,
@@ -36,7 +36,7 @@ describe('affiliateFeeUtils', () => {
FILLABLE_AMOUNTS,
);
const fakeOrdersWithFees = getSignedOrdersWithFees(
const fakeOrdersWithFees = getPartialSignedOrdersWithFees(
FAKE_MAKER_ASSET_DATA,
FAKE_TAKER_ASSET_DATA,
NULL_ADDRESS,

View File

@@ -2,7 +2,7 @@ import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { FillScenarios } from '@0x/fill-scenarios';
import { assetDataUtils } from '@0x/order-utils';
import { MarketOperation } from '@0x/types';
import { MarketOperation, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import 'mocha';
@@ -11,29 +11,39 @@ import { ForwarderSwapQuoteConsumer } from '../src/quote_consumers/forwarder_swa
import { chaiSetup } from './utils/chai_setup';
import { migrateOnceAsync } from './utils/migrate';
import { getFullyFillableSwapQuoteWithNoFees, getSignedOrdersWithNoFees } from './utils/swap_quote';
import { getFullyFillableSwapQuoteWithNoFees, getSignedOrdersWithNoFeesAsync } from './utils/swap_quote';
import { provider, web3Wrapper } from './utils/web3_wrapper';
import { SwapQuote } from '../src';
import { ContractWrappers, ContractAddresses } from '@0x/contract-wrappers';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const FILLABLE_AMOUNTS = [new BigNumber(5), new BigNumber(10)];
const ONE_ETH_IN_WEI = new BigNumber(1000000000000000000);
const TESTRPC_NETWORK_ID = 50;
const MARKET_OPERATION = MarketOperation.Sell;
const FILLABLE_AMOUNTS = [new BigNumber(2), new BigNumber(3), new BigNumber(5)].map(value => value.multipliedBy(ONE_ETH_IN_WEI));
const FILLABLE_FEE_AMOUNTS = [new BigNumber(1), new BigNumber(1), new BigNumber(1)].map(value => value.multipliedBy(ONE_ETH_IN_WEI));
describe('ForwarderSwapQuoteConsumer', () => {
let contractWrappers: ContractWrappers;
let userAddresses: string[];
let coinbaseAddress: string;
let makerAddress: string;
let takerAddress: string;
let fillScenarios: FillScenarios;
let feeRecipient: string;
let makerTokenAddress: string;
let takerTokenAddress: string;
let makerAssetData: string;
let takerAssetData: string;
let wethAssetData: string;
let contractAddresses: ContractAddresses;
const networkId = TESTRPC_NETWORK_ID;
before(async () => {
const contractAddresses = await migrateOnceAsync();
contractAddresses = await migrateOnceAsync();
await blockchainLifecycle.startAsync();
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
fillScenarios = new FillScenarios(
@@ -44,8 +54,13 @@ describe('ForwarderSwapQuoteConsumer', () => {
contractAddresses.erc20Proxy,
contractAddresses.erc721Proxy,
);
[makerAddress, takerAddress, feeRecipient] = userAddresses;
const [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
const config = {
networkId,
contractAddresses,
};
contractWrappers = new ContractWrappers(provider, config);
[coinbaseAddress, takerAddress, makerAddress, feeRecipient] = userAddresses;
[makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
[makerAssetData, takerAssetData, wethAssetData] = [
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
@@ -65,7 +80,8 @@ describe('ForwarderSwapQuoteConsumer', () => {
describe('validation', () => {
it('should throw if swapQuote provided is not a valid forwarder SwapQuote (taker asset is wEth', async () => {
const invalidSignedOrders = getSignedOrdersWithNoFees(
const invalidSignedOrders = await getSignedOrdersWithNoFeesAsync(
provider,
makerAssetData,
takerAssetData,
makerAddress,
@@ -82,17 +98,98 @@ describe('ForwarderSwapQuoteConsumer', () => {
networkId,
});
expect(
swapQuoteConsumer.executeSwapQuoteOrThrowAsync(invalidSwapQuote, {}),
swapQuoteConsumer.executeSwapQuoteOrThrowAsync(invalidSwapQuote, { takerAddress }),
).to.be.rejectedWith(`Expected quote.orders[0] to have takerAssetData set as ${wethAssetData}, but is ${takerAssetData}`);
});
});
it('should perform a marketSell execution when provided a MarketSell type swapQuote', () => {});
it('should perform a marketBuy execution when provided a MarketBuy type swapQuote', () => {});
describe('valid swap quote', () => {
let orders: SignedOrder[];
let marketSellSwapQuote: SwapQuote;
let marketBuySwapQuote: SwapQuote;
let swapQuoteConsumer: ForwarderSwapQuoteConsumer;
let erc20ProxyAddress: string;
beforeEach(async () => {
it('should perform a marketSell execution with affiliate fees', () => {});
it('should perform a marketSell execution with provided ethAmount in options', () => {});
it('should perform a marketSell execution with provided takerAddress in options', () => {});
const UNLIMITED_ALLOWANCE = contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
erc20ProxyAddress = contractWrappers.erc20Proxy.address;
const totalFillableAmount = FILLABLE_AMOUNTS.reduce((a: BigNumber, c: BigNumber) => a.plus(c), new BigNumber(0));
await contractWrappers.erc20Token.transferAsync(makerTokenAddress, coinbaseAddress, makerAddress, totalFillableAmount);
await contractWrappers.erc20Token.setAllowanceAsync(makerTokenAddress, makerAddress, erc20ProxyAddress, UNLIMITED_ALLOWANCE);
orders = await getSignedOrdersWithNoFeesAsync(
provider,
makerAssetData,
wethAssetData,
makerAddress,
takerAddress,
FILLABLE_AMOUNTS,
);
marketSellSwapQuote = getFullyFillableSwapQuoteWithNoFees(
makerAssetData,
wethAssetData,
orders,
MarketOperation.Sell,
);
marketBuySwapQuote = getFullyFillableSwapQuoteWithNoFees(
makerAssetData,
wethAssetData,
orders,
MarketOperation.Buy,
);
swapQuoteConsumer = new ForwarderSwapQuoteConsumer(provider, {
networkId,
});
});
/*
* Testing that SwapQuoteConsumer logic correctly performs a execution (doesn't throw or revert)
* Does not test the validity of the state change performed by the forwarder smart contract
*/
it('should perform a marketSell execution when provided a MarketSell type swapQuote', async () => {
const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
const takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
console.log(makerBalance, takerBalance);
const preEthBalanceMaker = await web3Wrapper.getBalanceInWeiAsync(makerAddress);
const preEthBalanceTaker = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
console.log('maker eth balance', preEthBalanceMaker, 'taker eth balance', preEthBalanceTaker);
expect(
swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketSellSwapQuote, { takerAddress }),
).to.not.be.rejected();
const ethBalanceMaker = await web3Wrapper.getBalanceInWeiAsync(makerAddress);
const ethBalanceTaker = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
console.log('maker eth balance', ethBalanceMaker, 'taker eth balance', ethBalanceTaker);
const postMakerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
const postTakerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
console.log(postMakerBalance, postTakerBalance);
});
it('should perform a marketBuy execution when provided a MarketBuy type swapQuote', async () => {
const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
const takerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
console.log(makerBalance, takerBalance);
const preEthBalanceMaker = await web3Wrapper.getBalanceInWeiAsync(makerAddress);
const preEthBalanceTaker = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
console.log('maker eth balance', preEthBalanceMaker, 'taker eth balance', preEthBalanceTaker);
expect(
swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketBuySwapQuote, { takerAddress }),
).to.not.be.rejected();
const ethBalanceMaker = await web3Wrapper.getBalanceInWeiAsync(makerAddress);
const ethBalanceTaker = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
console.log('maker eth balance', ethBalanceMaker, 'taker eth balance', ethBalanceTaker);
const postMakerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
const postTakerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, takerAddress);
console.log(postMakerBalance, postTakerBalance);
});
it('should perform a marketSell execution with affiliate fees', () => {});
it('should perform a marketSell execution with provided ethAmount in options', () => {});
it('should throw on a marketSell execution with provided ethAmount that is lower than bestCaseQuoteInfo.totalTakerAssetAmount in options', () => {});
it('should perform a marketSell execution with provided takerAddress in options', () => {});
});
});
describe('getSmartContractParamsOrThrow', () => {

View File

@@ -0,0 +1,172 @@
import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { FillScenarios } from '@0x/fill-scenarios';
import { assetDataUtils } from '@0x/order-utils';
import { MarketOperation, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import 'mocha';
import { chaiSetup } from './utils/chai_setup';
import { migrateOnceAsync } from './utils/migrate';
import { getFullyFillableSwapQuoteWithNoFees, getSignedOrdersWithNoFeesAsync } from './utils/swap_quote';
import { provider, web3Wrapper } from './utils/web3_wrapper';
import { SwapQuote, SwapQuoteConsumer } from '../src';
import { ContractWrappers, ContractAddresses } from '@0x/contract-wrappers';
import { swapQuoteConsumerUtils } from '../src/utils/swap_quote_consumer_utils';
import { ConsumerType } from '../src/types';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const ONE_ETH_IN_WEI = new BigNumber(1000000000000000000);
const TESTRPC_NETWORK_ID = 50;
const MARKET_OPERATION = MarketOperation.Sell;
const FILLABLE_AMOUNTS = [new BigNumber(2), new BigNumber(3), new BigNumber(5)].map(value => value.multipliedBy(ONE_ETH_IN_WEI));
const LARGE_FILLABLE_AMOUNTS = [new BigNumber(20), new BigNumber(20), new BigNumber(20)].map(value => value.multipliedBy(ONE_ETH_IN_WEI));
describe('swapQuoteConsumerUtils', () => {
let contractWrappers: ContractWrappers;
let userAddresses: string[];
let makerAddress: string;
let takerAddress: string;
let feeRecipient: string;
let makerTokenAddress: string;
let takerTokenAddress: string;
let makerAssetData: string;
let takerAssetData: string;
let wethAssetData: string;
let contractAddresses: ContractAddresses;
const networkId = TESTRPC_NETWORK_ID;
before(async () => {
contractAddresses = await migrateOnceAsync();
await blockchainLifecycle.startAsync();
userAddresses = await web3Wrapper.getAvailableAddressesAsync();
const config = {
networkId,
contractAddresses,
};
contractWrappers = new ContractWrappers(provider, config);
[takerAddress, makerAddress, feeRecipient] = userAddresses;
[makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
[makerAssetData, takerAssetData, wethAssetData] = [
assetDataUtils.encodeERC20AssetData(makerTokenAddress),
assetDataUtils.encodeERC20AssetData(takerTokenAddress),
assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken),
];
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('getConsumerTypeForSwapQuoteAsync', () => {
let forwarderOrders: SignedOrder[];
let exchangeOrders: SignedOrder[];
let largeForwarderOrders: SignedOrder[];
let forwarderSwapQuote: SwapQuote;
let exchangeSwapQuote: SwapQuote;
let largeForwarderSwapQuote: SwapQuote;
let swapQuoteConsumer: SwapQuoteConsumer;
beforeEach(async () => {
swapQuoteConsumer = new SwapQuoteConsumer(provider, { networkId });
exchangeOrders = await getSignedOrdersWithNoFeesAsync(
provider,
makerAssetData,
takerAssetData,
makerAddress,
takerAddress,
FILLABLE_AMOUNTS,
);
forwarderOrders = await getSignedOrdersWithNoFeesAsync(
provider,
makerAssetData,
wethAssetData,
makerAddress,
takerAddress,
FILLABLE_AMOUNTS,
);
largeForwarderOrders = await getSignedOrdersWithNoFeesAsync(
provider,
makerAssetData,
wethAssetData,
makerAddress,
takerAddress,
LARGE_FILLABLE_AMOUNTS,
);
forwarderSwapQuote = getFullyFillableSwapQuoteWithNoFees(
makerAssetData,
wethAssetData,
forwarderOrders,
MarketOperation.Sell,
);
largeForwarderSwapQuote = getFullyFillableSwapQuoteWithNoFees(
makerAssetData,
wethAssetData,
largeForwarderOrders,
MarketOperation.Sell,
);
exchangeSwapQuote = getFullyFillableSwapQuoteWithNoFees(
makerAssetData,
takerAssetData,
exchangeOrders,
MarketOperation.Sell,
);
});
it('should return exchange consumer if takerAsset is not wEth', async () => {
const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync(
exchangeSwapQuote,
contractWrappers,
provider,
{ takerAddress },
);
expect(consumerType).to.equal(ConsumerType.Exchange);
});
it('should return forwarder consumer if takerAsset is wEth and have enough eth balance', async () => {
const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync(
forwarderSwapQuote,
contractWrappers,
provider,
{ takerAddress },
);
expect(consumerType).to.equal(ConsumerType.Forwarder);
});
it('should return exchange consumer if takerAsset is wEth and taker has enough weth', async () => {
const etherInWei = (new BigNumber(20)).multipliedBy(ONE_ETH_IN_WEI);
await contractWrappers.etherToken.depositAsync(contractAddresses.etherToken, etherInWei, takerAddress);
const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync(
forwarderSwapQuote,
contractWrappers,
provider,
{ takerAddress },
);
expect(consumerType).to.equal(ConsumerType.Exchange);
});
it('should return forwarder consumer if takerAsset is wEth and takerAddress has no available balance in either weth or eth (defaulting behavior)',async () => {
const etherInWei = (new BigNumber(50)).multipliedBy(ONE_ETH_IN_WEI);
await contractWrappers.etherToken.depositAsync(contractAddresses.etherToken, etherInWei, takerAddress);
const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync(
largeForwarderSwapQuote,
contractWrappers,
provider,
{ takerAddress },
);
expect(consumerType).to.equal(ConsumerType.Forwarder);
});
});
});

View File

@@ -1,13 +1,37 @@
import { orderFactory } from '@0x/order-utils/lib/src/order_factory';
import { MarketOperation, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { SupportedProvider } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import { SwapQuote } from '../../src/types';
import { constants } from '../../src/constants';
const ZERO_BIG_NUMBER = new BigNumber(0);
export const getSignedOrdersWithNoFees = (
export const getSignedOrdersWithNoFeesAsync = async (
provider: SupportedProvider,
makerAssetData: string,
takerAssetData: string,
makerAddress: string,
takerAddress: string,
fillableAmounts: BigNumber[],
): Promise<SignedOrder[]> => {
const promises = _.map(fillableAmounts, async (fillableAmount: BigNumber) =>
orderFactory.createSignedOrderAsync(
provider,
makerAddress,
fillableAmount,
makerAssetData,
fillableAmount,
takerAssetData,
constants.NULL_ADDRESS,
),
);
return Promise.all(promises);
};
export const getPartialSignedOrdersWithNoFees = (
makerAssetData: string,
takerAssetData: string,
makerAddress: string,
@@ -25,7 +49,7 @@ export const getSignedOrdersWithNoFees = (
);
};
export const getSignedOrdersWithFees = (
export const getPartialSignedOrdersWithFees = (
makerAssetData: string,
takerAssetData: string,
makerAddress: string,
@@ -33,7 +57,7 @@ export const getSignedOrdersWithFees = (
fillableAmounts: BigNumber[],
takerFees: BigNumber[],
): SignedOrder[] => {
const orders = getSignedOrdersWithNoFees(
const orders = getPartialSignedOrdersWithNoFees(
makerAssetData,
takerAssetData,
makerAddress,