added more unit tests for PLP DEX sampling

This commit is contained in:
Daniel Pyrathon 2020-02-27 16:03:44 -08:00
parent 8be60e2ff5
commit 9608d8fb46
3 changed files with 133 additions and 34 deletions

View File

@ -75,6 +75,40 @@ const samplerOperations = {
}, },
}; };
}, },
getPLPSellQuotes(
plpRegistryAddress: string,
takerToken: string,
makerToken: string,
takerFillAmounts: BigNumber[],
): BatchedOperation<BigNumber[]> {
return {
encodeCall: contract => {
return contract
.sampleSellsFromLiquidityProviderRegistry(plpRegistryAddress, takerToken, makerToken, takerFillAmounts)
.getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromLiquidityProviderRegistry', callResults);
},
};
},
getPLPBuyQuotes(
plpRegistryAddress: string,
takerToken: string,
makerToken: string,
makerFillAmounts: BigNumber[],
): BatchedOperation<BigNumber[]> {
return {
encodeCall: contract => {
return contract
.sampleBuysFromLiquidityProviderRegistry(plpRegistryAddress, takerToken, makerToken, makerFillAmounts)
.getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
return contract.getABIDecodedReturnData<BigNumber[]>('sampleBuysFromLiquidityProviderRegistry', callResults);
},
};
},
getEth2DaiSellQuotes( getEth2DaiSellQuotes(
makerToken: string, makerToken: string,
takerToken: string, takerToken: string,
@ -186,12 +220,12 @@ const samplerOperations = {
}, },
getLiquidityProviderFromRegistry( getLiquidityProviderFromRegistry(
registryAddress: string, registryAddress: string,
makerToken: string,
takerToken: string, takerToken: string,
makerToken: string,
): BatchedOperation<string> { ): BatchedOperation<string> {
return { return {
encodeCall: contract => { encodeCall: contract => {
return contract.getLiquidityProviderFromRegistry(registryAddress, makerToken, takerToken).getABIEncodedTransactionData() return contract.getLiquidityProviderFromRegistry(registryAddress, takerToken, makerToken).getABIEncodedTransactionData();
}, },
handleCallResultsAsync: async (contract, callResults) => { handleCallResultsAsync: async (contract, callResults) => {
return contract.getABIDecodedReturnData<string>('getLiquidityProviderFromRegistry', callResults); return contract.getABIDecodedReturnData<string>('getLiquidityProviderFromRegistry', callResults);
@ -203,6 +237,7 @@ const samplerOperations = {
makerToken: string, makerToken: string,
takerToken: string, takerToken: string,
takerFillAmounts: BigNumber[], takerFillAmounts: BigNumber[],
plpRegistryAddress?: string | undefined,
): BatchedOperation<DexSample[][]> { ): BatchedOperation<DexSample[][]> {
const subOps = sources const subOps = sources
.map(source => { .map(source => {
@ -229,8 +264,15 @@ const samplerOperations = {
takerFillAmounts, takerFillAmounts,
); );
} }
} else if (source === ERC20BridgeSource.Plp) {
if (plpRegistryAddress === undefined) {
throw new Error('Cannot sample liquidity from a PLP liquidity pool, if a registry is not provided.');
}
batchedOperation = samplerOperations.getPLPSellQuotes(
plpRegistryAddress, takerToken, makerToken, takerFillAmounts,
);
} else { } else {
throw new Error(`Unsupported sell sample source: ${source}`); throw new Error(`Unsupported sell sample source: ${source}`);
} }
return { batchedOperation, source }; return { batchedOperation, source };
}) })
@ -265,12 +307,20 @@ const samplerOperations = {
makerToken: string, makerToken: string,
takerToken: string, takerToken: string,
makerFillAmounts: BigNumber[], makerFillAmounts: BigNumber[],
plpRegistryAddress?: string | undefined,
): BatchedOperation<DexSample[][]> { ): BatchedOperation<DexSample[][]> {
const subOps = sources.map(source => { const subOps = sources.map(source => {
if (source === ERC20BridgeSource.Eth2Dai) { if (source === ERC20BridgeSource.Eth2Dai) {
return samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts); return samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts);
} else if (source === ERC20BridgeSource.Uniswap) { } else if (source === ERC20BridgeSource.Uniswap) {
return samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts); return samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
} else if (source === ERC20BridgeSource.Plp) {
if (plpRegistryAddress === undefined) {
throw new Error('Cannot sample liquidity from a PLP liquidity pool, if a registry is not provided.');
}
return samplerOperations.getPLPBuyQuotes(
plpRegistryAddress, takerToken, makerToken, makerFillAmounts,
);
} else { } else {
throw new Error(`Unsupported buy sample source: ${source}`); throw new Error(`Unsupported buy sample source: ${source}`);
} }

View File

@ -31,6 +31,7 @@ export enum ERC20BridgeSource {
CurveUsdcDai = 'Curve_USDC_DAI', CurveUsdcDai = 'Curve_USDC_DAI',
CurveUsdcDaiUsdt = 'Curve_USDC_DAI_USDT', CurveUsdcDaiUsdt = 'Curve_USDC_DAI_USDT',
CurveUsdcDaiUsdtTusd = 'Curve_USDC_DAI_USDT_TUSD', CurveUsdcDaiUsdtTusd = 'Curve_USDC_DAI_USDT_TUSD',
Plp = 'PLP',
} }
// Internal `fillData` field for `Fill` objects. // Internal `fillData` field for `Fill` objects.

View File

@ -1,14 +1,14 @@
import { constants, expect, getRandomFloat, getRandomInteger, randomAddress, provider, txDefaults } from '@0x/contracts-test-utils'; import { constants, expect, getRandomFloat, getRandomInteger, provider, randomAddress, txDefaults } from '@0x/contracts-test-utils';
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
import { SignedOrder } from '@0x/types'; import { SignedOrder } from '@0x/types';
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils'; import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler'; import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler';
import { ERC20BridgeSource } from '../src/utils/market_operation_utils/types'; import { ERC20BridgeSource, DexSample } from '../src/utils/market_operation_utils/types';
import { MockSamplerContract } from './utils/mock_sampler_contract'; import { MockSamplerContract } from './utils/mock_sampler_contract';
import { DummyLiquidityProviderRegistryContract, ERC20BridgeSamplerContract, IERC20BridgeSamplerContract } from '@0x/contract-wrappers'; import { DummyLiquidityProviderRegistryContract, ERC20BridgeSamplerContract, IERC20BridgeSamplerContract, DummyLiquidityProviderContract } from '@0x/contract-wrappers';
import { artifacts as erc20BridgeSamplerArtifacts } from '@0x/contracts-erc20-bridge-sampler/lib/src/artifacts'; import { artifacts as erc20BridgeSamplerArtifacts } from '@0x/contracts-erc20-bridge-sampler/lib/src/artifacts';
const CHAIN_ID = 1; const CHAIN_ID = 1;
@ -329,42 +329,90 @@ describe('DexSampler tests', () => {
expect(quotes).to.deep.eq(expectedQuotes); expect(quotes).to.deep.eq(expectedQuotes);
}); });
it.only('getLiquidityProviderFromRegistry()', async () => { describe.only('PLP Operations', () => {
const xAsset = randomAddress(); const xAsset = randomAddress();
const yAsset = randomAddress(); const yAsset = randomAddress();
const zAsset = randomAddress(); const zAsset = randomAddress();
const liquidityPool1 = randomAddress(); const liquidityPool1 = randomAddress();
const liquidityPool2 = randomAddress(); const liquidityPool2 = randomAddress();
// Deploy Registry let registryContract: DummyLiquidityProviderRegistryContract;
const registryContract = await DummyLiquidityProviderRegistryContract.deployFrom0xArtifactAsync( let samplerContract: ERC20BridgeSamplerContract;
erc20BridgeSamplerArtifacts.DummyLiquidityProviderRegistry, beforeEach(async () => {
provider, registryContract = await DummyLiquidityProviderRegistryContract.deployFrom0xArtifactAsync(
txDefaults, erc20BridgeSamplerArtifacts.DummyLiquidityProviderRegistry,
{}, provider,
); txDefaults,
// Write 2 new liquidity pools {},
await registryContract.setLiquidityProviderForMarket(xAsset, yAsset, liquidityPool1).awaitTransactionSuccessAsync(); );
await registryContract.setLiquidityProviderForMarket(xAsset, zAsset, liquidityPool2).awaitTransactionSuccessAsync(); samplerContract = await ERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
erc20BridgeSamplerArtifacts.ERC20BridgeSampler,
provider,
txDefaults,
{},
);
});
it('getLiquidityProviderFromRegistry()', async () => {
// Deploy Registry
// Write 2 new liquidity pools
await registryContract.setLiquidityProviderForMarket(xAsset, yAsset, liquidityPool1).awaitTransactionSuccessAsync().txHashPromise;
await registryContract.setLiquidityProviderForMarket(xAsset, zAsset, liquidityPool2).awaitTransactionSuccessAsync().txHashPromise;
// Deploy the sampler // Deploy the sampler
const samplerContract = await ERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
erc20BridgeSamplerArtifacts.ERC20BridgeSampler,
provider,
txDefaults,
{},
);
// Test multiple combinations: 2 pools that are present, 1 pool that is not present. // Test multiple combinations: 2 pools that are present, 1 pool that is not present.
const dexOrderSampler = new DexOrderSampler(new IERC20BridgeSamplerContract(samplerContract.address, provider)); const dexOrderSampler = new DexOrderSampler(new IERC20BridgeSamplerContract(samplerContract.address, provider));
const [xyPool, xzPool, yzPool] = await dexOrderSampler.executeBatchAsync([ const [xyPool, xzPool, yzPool] = await dexOrderSampler.executeBatchAsync([
DexOrderSampler.ops.getLiquidityProviderFromRegistry(registryContract.address, xAsset, yAsset), DexOrderSampler.ops.getLiquidityProviderFromRegistry(registryContract.address, xAsset, yAsset),
DexOrderSampler.ops.getLiquidityProviderFromRegistry(registryContract.address, xAsset, zAsset), DexOrderSampler.ops.getLiquidityProviderFromRegistry(registryContract.address, xAsset, zAsset),
DexOrderSampler.ops.getLiquidityProviderFromRegistry(registryContract.address, yAsset, zAsset), DexOrderSampler.ops.getLiquidityProviderFromRegistry(registryContract.address, yAsset, zAsset),
]); ]);
expect(xyPool).to.eql(liquidityPool1); expect(xyPool).to.eql(liquidityPool1);
expect(xzPool).to.eql(liquidityPool2); expect(xzPool).to.eql(liquidityPool2);
expect(yzPool).to.eql(NULL_ADDRESS); expect(yzPool).to.eql(NULL_ADDRESS);
});
it('is able to sample DEX liquidity from PLP', async () => {
const fakeLiquidityPool = await DummyLiquidityProviderContract.deployFrom0xArtifactAsync(
erc20BridgeSamplerArtifacts.DummyLiquidityProvider,
provider,
txDefaults,
{},
);
await registryContract.setLiquidityProviderForMarket(xAsset, yAsset, fakeLiquidityPool.address).awaitTransactionSuccessAsync().txHashPromise;
const dexOrderSampler = new DexOrderSampler(new IERC20BridgeSamplerContract(samplerContract.address, provider));
const [buyQuotes, sellQuotes] = await dexOrderSampler.executeBatchAsync([
DexOrderSampler.ops.getBuyQuotes(
[ERC20BridgeSource.Plp],
xAsset,
yAsset,
[new BigNumber(10), new BigNumber(100)],
registryContract.address,
),
DexOrderSampler.ops.getSellQuotes(
[ERC20BridgeSource.Plp],
xAsset,
yAsset,
[new BigNumber(10), new BigNumber(100), new BigNumber(500)],
registryContract.address,
),
]);
expect(buyQuotes.length).to.eql(1);
const plpBuyQuotes: DexSample[] = buyQuotes[0];
expect(plpBuyQuotes.length).to.eql(2);
for(const quote of plpBuyQuotes) {
expect(quote.source).to.bignumber.eql(ERC20BridgeSource.Plp);
expect(quote.input.plus(1)).to.bignumber.eql(quote.output);
}
expect(sellQuotes.length).to.eql(1);
const plpSellQuotes: DexSample[] = sellQuotes[0];
expect(plpSellQuotes.length).to.eql(3);
for(const quote of plpSellQuotes) {
expect(quote.source).to.bignumber.eql(ERC20BridgeSource.Plp);
expect(quote.input.minus(1)).to.bignumber.eql(quote.output);
}
})
}); });
}); });