diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index c4d69e7f79..325458abbb 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -17,6 +17,10 @@ { "note": "Add `unoptimizedPath` to OptimizerResult", "pr": 62 + }, + { + "note": "Enable PLP VIP feature and add gasCost field to LiquidityProviderRegistry", + "pr": 65 } ] }, diff --git a/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts b/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts index 0295ad93bf..19d4241944 100644 --- a/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts +++ b/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts @@ -34,7 +34,7 @@ import { getSwapMinBuyAmount } from './utils'; // tslint:disable-next-line:custom-no-magic-numbers const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); -const { NULL_ADDRESS, ZERO_AMOUNT } = constants; +const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants; export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { public readonly provider: ZeroExProvider; @@ -131,6 +131,26 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { }; } + if (isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.LiquidityProvider])) { + const target = quote.orders[0].makerAddress; + return { + calldataHexString: this._exchangeProxy + .sellToLiquidityProvider( + isFromETH ? ETH_TOKEN_ADDRESS : sellToken, + isToETH ? ETH_TOKEN_ADDRESS : buyToken, + target, + NULL_ADDRESS, + sellAmount, + minBuyAmount, + NULL_BYTES, + ) + .getABIEncodedTransactionData(), + ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT, + toAddress: this._exchangeProxy.address, + allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget, + }; + } + // Build up the transforms. const transforms = []; if (isFromETH) { diff --git a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts index 906ecae817..6802fd52be 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -13,6 +13,7 @@ import { FeeSchedule, FillData, GetMarketOrdersOpts, + LiquidityProviderFillData, LiquidityProviderRegistry, MultiHopFillData, SnowSwapFillData, @@ -445,7 +446,9 @@ export const BRIDGE_ADDRESSES_BY_CHAIN: { [chainId in ChainId]: BridgeContractAd export const DEFAULT_GAS_SCHEDULE: Required = { [ERC20BridgeSource.Native]: () => 150e3, [ERC20BridgeSource.Uniswap]: () => 90e3, - [ERC20BridgeSource.LiquidityProvider]: () => 140e3, + [ERC20BridgeSource.LiquidityProvider]: fillData => { + return (fillData as LiquidityProviderFillData).gasCost; + }, [ERC20BridgeSource.Eth2Dai]: () => 400e3, [ERC20BridgeSource.Kyber]: () => 450e3, [ERC20BridgeSource.Curve]: fillData => { diff --git a/packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts b/packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts index e3bda41873..700d8ddd53 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/liquidity_provider_utils.ts @@ -7,6 +7,6 @@ export function getLiquidityProvidersForPair( makerToken: string, ): string[] { return Object.entries(registry) - .filter(([, tokens]) => [makerToken, takerToken].every(t => tokens.includes(t))) + .filter(([, plp]) => [makerToken, takerToken].every(t => plp.tokens.includes(t))) .map(([providerAddress]) => providerAddress); } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts index deb95c071e..134efb9a12 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts @@ -235,7 +235,10 @@ export class SamplerOperations { ): SourceQuoteOperation { return new SamplerContractOperation({ source: ERC20BridgeSource.LiquidityProvider, - fillData: { poolAddress: providerAddress }, + fillData: { + poolAddress: providerAddress, + gasCost: this.liquidityProviderRegistry[providerAddress].gasCost, + }, contract: this._samplerContract, function: this._samplerContract.sampleSellsFromLiquidityProvider, params: [providerAddress, takerToken, makerToken, takerFillAmounts], @@ -250,7 +253,10 @@ export class SamplerOperations { ): SourceQuoteOperation { return new SamplerContractOperation({ source: ERC20BridgeSource.LiquidityProvider, - fillData: { poolAddress: providerAddress }, + fillData: { + poolAddress: providerAddress, + gasCost: this.liquidityProviderRegistry[providerAddress].gasCost, + }, contract: this._samplerContract, function: this._samplerContract.sampleBuysFromLiquidityProvider, params: [providerAddress, takerToken, makerToken, makerFillAmounts], diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index 0bfb6a1ac6..f90daf4ca9 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -132,6 +132,7 @@ export interface ShellFillData extends FillData { export interface LiquidityProviderFillData extends FillData { poolAddress: string; + gasCost: number; } export interface BancorFillData extends FillData { @@ -383,7 +384,10 @@ export interface TokenAdjacencyGraph { } export interface LiquidityProviderRegistry { - [address: string]: [string, string]; + [address: string]: { + tokens: string[]; + gasCost: number; + }; } export interface GenerateOptimizedOrdersOpts { diff --git a/packages/asset-swapper/test/dex_sampler_test.ts b/packages/asset-swapper/test/dex_sampler_test.ts index 1e65ac341a..b5b32599df 100644 --- a/packages/asset-swapper/test/dex_sampler_test.ts +++ b/packages/asset-swapper/test/dex_sampler_test.ts @@ -156,6 +156,7 @@ describe('DexSampler tests', () => { const expectedMakerToken = randomAddress(); const expectedTakerToken = randomAddress(); const poolAddress = randomAddress(); + const gasCost = 123; const sampler = new MockSamplerContract({ sampleSellsFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => { expect(providerAddress).to.eq(poolAddress); @@ -172,7 +173,7 @@ describe('DexSampler tests', () => { undefined, undefined, undefined, - { [poolAddress]: [expectedMakerToken, expectedTakerToken] }, + { [poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost } }, ); const [result] = await dexOrderSampler.executeAsync( dexOrderSampler.getSellQuotes( @@ -188,7 +189,7 @@ describe('DexSampler tests', () => { source: 'LiquidityProvider', output: toBaseUnitAmount(1001), input: toBaseUnitAmount(1000), - fillData: { poolAddress }, + fillData: { poolAddress, gasCost }, }, ], ]); @@ -198,6 +199,7 @@ describe('DexSampler tests', () => { const expectedMakerToken = randomAddress(); const expectedTakerToken = randomAddress(); const poolAddress = randomAddress(); + const gasCost = 321; const sampler = new MockSamplerContract({ sampleBuysFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => { expect(providerAddress).to.eq(poolAddress); @@ -214,7 +216,7 @@ describe('DexSampler tests', () => { undefined, undefined, undefined, - { [poolAddress]: [expectedMakerToken, expectedTakerToken] }, + { [poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost } }, ); const [result] = await dexOrderSampler.executeAsync( dexOrderSampler.getBuyQuotes( @@ -230,7 +232,7 @@ describe('DexSampler tests', () => { source: 'LiquidityProvider', output: toBaseUnitAmount(999), input: toBaseUnitAmount(1000), - fillData: { poolAddress }, + fillData: { poolAddress, gasCost }, }, ], ]); diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index b450b3d2f2..28f49348e8 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -1274,7 +1274,10 @@ describe('MarketOperationUtils tests', () => { .poolAddress; const rates: RatesBySource = {}; rates[ERC20BridgeSource.LiquidityProvider] = [1, 1, 1, 1]; - MOCK_SAMPLER.liquidityProviderRegistry[liquidityProviderAddress] = [MAKER_TOKEN, TAKER_TOKEN]; + MOCK_SAMPLER.liquidityProviderRegistry[liquidityProviderAddress] = { + tokens: [MAKER_TOKEN, TAKER_TOKEN], + gasCost: 0, + }; replaceSamplerOps({ getOrderFillableTakerAmounts: () => [constants.ZERO_AMOUNT], getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates), @@ -1317,7 +1320,10 @@ describe('MarketOperationUtils tests', () => { [ERC20BridgeSource.Uniswap]: [1, 1, 1, 1], [ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999], }; - MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN]; + MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = { + tokens: [MAKER_TOKEN, TAKER_TOKEN], + gasCost: 0, + }; replaceSamplerOps({ getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates), getMedianSellRate: createGetMedianSellRate(ETH_TO_MAKER_RATE), @@ -1736,7 +1742,10 @@ describe('MarketOperationUtils tests', () => { [ERC20BridgeSource.Uniswap]: [1, 1, 1, 1], [ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999], }; - MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN]; + MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = { + tokens: [MAKER_TOKEN, TAKER_TOKEN], + gasCost: 0, + }; replaceSamplerOps({ getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates), getMedianSellRate: createGetMedianSellRate(ETH_TO_TAKER_RATE),