feat: asset-swapper use ethToInputRate when ethToOutputRate is unavailable (#2660)
This commit is contained in:
parent
71cde281b9
commit
d0e9081852
@ -41,6 +41,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Fix depth buy scale",
|
"note": "Fix depth buy scale",
|
||||||
"pr": 2659
|
"pr": 2659
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Adjust fill by ethToInputRate when ethToOutputRate is 0",
|
||||||
|
"pr": 2660
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,7 @@ export function createFillPaths(opts: {
|
|||||||
dexQuotes?: DexSample[][];
|
dexQuotes?: DexSample[][];
|
||||||
targetInput?: BigNumber;
|
targetInput?: BigNumber;
|
||||||
ethToOutputRate?: BigNumber;
|
ethToOutputRate?: BigNumber;
|
||||||
|
ethToInputRate?: BigNumber;
|
||||||
excludedSources?: ERC20BridgeSource[];
|
excludedSources?: ERC20BridgeSource[];
|
||||||
feeSchedule?: FeeSchedule;
|
feeSchedule?: FeeSchedule;
|
||||||
}): Fill[][] {
|
}): Fill[][] {
|
||||||
@ -26,8 +27,9 @@ export function createFillPaths(opts: {
|
|||||||
const orders = opts.orders || [];
|
const orders = opts.orders || [];
|
||||||
const dexQuotes = opts.dexQuotes || [];
|
const dexQuotes = opts.dexQuotes || [];
|
||||||
const ethToOutputRate = opts.ethToOutputRate || ZERO_AMOUNT;
|
const ethToOutputRate = opts.ethToOutputRate || ZERO_AMOUNT;
|
||||||
|
const ethToInputRate = opts.ethToInputRate || ZERO_AMOUNT;
|
||||||
// Create native fill paths.
|
// Create native fill paths.
|
||||||
const nativePath = nativeOrdersToPath(side, orders, opts.targetInput, ethToOutputRate, feeSchedule);
|
const nativePath = nativeOrdersToPath(side, orders, opts.targetInput, ethToOutputRate, ethToInputRate, feeSchedule);
|
||||||
// Create DEX fill paths.
|
// Create DEX fill paths.
|
||||||
const dexPaths = dexQuotesToPaths(side, dexQuotes, ethToOutputRate, feeSchedule);
|
const dexPaths = dexQuotesToPaths(side, dexQuotes, ethToOutputRate, feeSchedule);
|
||||||
return filterPaths([...dexPaths, nativePath].map(p => clipPathToInput(p, opts.targetInput)), excludedSources);
|
return filterPaths([...dexPaths, nativePath].map(p => clipPathToInput(p, opts.targetInput)), excludedSources);
|
||||||
@ -54,6 +56,7 @@ function nativeOrdersToPath(
|
|||||||
orders: SignedOrderWithFillableAmounts[],
|
orders: SignedOrderWithFillableAmounts[],
|
||||||
targetInput: BigNumber = POSITIVE_INF,
|
targetInput: BigNumber = POSITIVE_INF,
|
||||||
ethToOutputRate: BigNumber,
|
ethToOutputRate: BigNumber,
|
||||||
|
ethToInputRate: BigNumber,
|
||||||
fees: FeeSchedule,
|
fees: FeeSchedule,
|
||||||
): Fill[] {
|
): Fill[] {
|
||||||
const sourcePathId = hexUtils.random();
|
const sourcePathId = hexUtils.random();
|
||||||
@ -64,9 +67,10 @@ function nativeOrdersToPath(
|
|||||||
const takerAmount = fillableAmountsUtils.getTakerAssetAmountSwappedAfterOrderFees(order);
|
const takerAmount = fillableAmountsUtils.getTakerAssetAmountSwappedAfterOrderFees(order);
|
||||||
const input = side === MarketOperation.Sell ? takerAmount : makerAmount;
|
const input = side === MarketOperation.Sell ? takerAmount : makerAmount;
|
||||||
const output = side === MarketOperation.Sell ? makerAmount : takerAmount;
|
const output = side === MarketOperation.Sell ? makerAmount : takerAmount;
|
||||||
const penalty = ethToOutputRate.times(
|
const fee = fees[ERC20BridgeSource.Native] === undefined ? 0 : fees[ERC20BridgeSource.Native]!();
|
||||||
fees[ERC20BridgeSource.Native] === undefined ? 0 : fees[ERC20BridgeSource.Native]!(),
|
const outputPenalty = !ethToOutputRate.isZero()
|
||||||
);
|
? ethToOutputRate.times(fee)
|
||||||
|
: ethToInputRate.times(fee).times(output.dividedToIntegerBy(input));
|
||||||
// targetInput can be less than the order size
|
// targetInput can be less than the order size
|
||||||
// whilst the penalty is constant, it affects the adjusted output
|
// whilst the penalty is constant, it affects the adjusted output
|
||||||
// only up until the target has been exhausted.
|
// only up until the target has been exhausted.
|
||||||
@ -76,7 +80,7 @@ function nativeOrdersToPath(
|
|||||||
// scale the clipped output inline with the input
|
// scale the clipped output inline with the input
|
||||||
const clippedOutput = clippedInput.dividedBy(input).times(output);
|
const clippedOutput = clippedInput.dividedBy(input).times(output);
|
||||||
const adjustedOutput =
|
const adjustedOutput =
|
||||||
side === MarketOperation.Sell ? clippedOutput.minus(penalty) : clippedOutput.plus(penalty);
|
side === MarketOperation.Sell ? clippedOutput.minus(outputPenalty) : clippedOutput.plus(outputPenalty);
|
||||||
const adjustedRate =
|
const adjustedRate =
|
||||||
side === MarketOperation.Sell ? adjustedOutput.div(clippedInput) : clippedInput.div(adjustedOutput);
|
side === MarketOperation.Sell ? adjustedOutput.div(clippedInput) : clippedInput.div(adjustedOutput);
|
||||||
// Skip orders with rates that are <= 0.
|
// Skip orders with rates that are <= 0.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ContractAddresses } from '@0x/contract-addresses';
|
import { ContractAddresses } from '@0x/contract-addresses';
|
||||||
|
import { ZERO_AMOUNT } from '@0x/order-utils';
|
||||||
import { RFQTIndicativeQuote } from '@0x/quote-server';
|
import { RFQTIndicativeQuote } from '@0x/quote-server';
|
||||||
import { SignedOrder } from '@0x/types';
|
import { SignedOrder } from '@0x/types';
|
||||||
import { BigNumber, NULL_ADDRESS } from '@0x/utils';
|
import { BigNumber, NULL_ADDRESS } from '@0x/utils';
|
||||||
@ -114,6 +115,17 @@ export class MarketOperationUtils {
|
|||||||
this._liquidityProviderRegistry,
|
this._liquidityProviderRegistry,
|
||||||
this._multiBridge,
|
this._multiBridge,
|
||||||
),
|
),
|
||||||
|
// Get ETH -> taker token price.
|
||||||
|
await DexOrderSampler.ops.getMedianSellRateAsync(
|
||||||
|
difference(FEE_QUOTE_SOURCES.concat(this._optionalSources()), _opts.excludedSources),
|
||||||
|
takerToken,
|
||||||
|
this._wethAddress,
|
||||||
|
ONE_ETHER,
|
||||||
|
this._wethAddress,
|
||||||
|
this._sampler.balancerPoolsCache,
|
||||||
|
this._liquidityProviderRegistry,
|
||||||
|
this._multiBridge,
|
||||||
|
),
|
||||||
// Get sell quotes for taker -> maker.
|
// Get sell quotes for taker -> maker.
|
||||||
await DexOrderSampler.ops.getSellQuotesAsync(
|
await DexOrderSampler.ops.getSellQuotesAsync(
|
||||||
difference(
|
difference(
|
||||||
@ -152,7 +164,7 @@ export class MarketOperationUtils {
|
|||||||
.then(async r => this._sampler.executeAsync(r));
|
.then(async r => this._sampler.executeAsync(r));
|
||||||
|
|
||||||
const [
|
const [
|
||||||
[orderFillableAmounts, liquidityProviderAddress, ethToMakerAssetRate, dexQuotes],
|
[orderFillableAmounts, liquidityProviderAddress, ethToMakerAssetRate, ethToTakerAssetRate, dexQuotes],
|
||||||
rfqtIndicativeQuotes,
|
rfqtIndicativeQuotes,
|
||||||
[balancerQuotes],
|
[balancerQuotes],
|
||||||
] = await Promise.all([samplerPromise, rfqtPromise, balancerPromise]);
|
] = await Promise.all([samplerPromise, rfqtPromise, balancerPromise]);
|
||||||
@ -174,6 +186,7 @@ export class MarketOperationUtils {
|
|||||||
nativeOrders,
|
nativeOrders,
|
||||||
orderFillableAmounts,
|
orderFillableAmounts,
|
||||||
ethToOutputRate: ethToMakerAssetRate,
|
ethToOutputRate: ethToMakerAssetRate,
|
||||||
|
ethToInputRate: ethToTakerAssetRate,
|
||||||
rfqtIndicativeQuotes,
|
rfqtIndicativeQuotes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -207,6 +220,17 @@ export class MarketOperationUtils {
|
|||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
),
|
),
|
||||||
|
// Get ETH -> maker token price.
|
||||||
|
await DexOrderSampler.ops.getMedianSellRateAsync(
|
||||||
|
difference(FEE_QUOTE_SOURCES.concat(this._optionalSources()), _opts.excludedSources),
|
||||||
|
makerToken,
|
||||||
|
this._wethAddress,
|
||||||
|
ONE_ETHER,
|
||||||
|
this._wethAddress,
|
||||||
|
this._sampler.balancerPoolsCache,
|
||||||
|
this._liquidityProviderRegistry,
|
||||||
|
this._multiBridge,
|
||||||
|
),
|
||||||
// Get ETH -> taker token price.
|
// Get ETH -> taker token price.
|
||||||
await DexOrderSampler.ops.getMedianSellRateAsync(
|
await DexOrderSampler.ops.getMedianSellRateAsync(
|
||||||
difference(FEE_QUOTE_SOURCES.concat(this._optionalSources()), _opts.excludedSources),
|
difference(FEE_QUOTE_SOURCES.concat(this._optionalSources()), _opts.excludedSources),
|
||||||
@ -255,7 +279,7 @@ export class MarketOperationUtils {
|
|||||||
_opts,
|
_opts,
|
||||||
);
|
);
|
||||||
const [
|
const [
|
||||||
[orderFillableAmounts, liquidityProviderAddress, ethToTakerAssetRate, dexQuotes],
|
[orderFillableAmounts, liquidityProviderAddress, ethToMakerAssetRate, ethToTakerAssetRate, dexQuotes],
|
||||||
rfqtIndicativeQuotes,
|
rfqtIndicativeQuotes,
|
||||||
[balancerQuotes],
|
[balancerQuotes],
|
||||||
] = await Promise.all([samplerPromise, rfqtPromise, balancerPromise]);
|
] = await Promise.all([samplerPromise, rfqtPromise, balancerPromise]);
|
||||||
@ -276,6 +300,7 @@ export class MarketOperationUtils {
|
|||||||
nativeOrders,
|
nativeOrders,
|
||||||
orderFillableAmounts,
|
orderFillableAmounts,
|
||||||
ethToOutputRate: ethToTakerAssetRate,
|
ethToOutputRate: ethToTakerAssetRate,
|
||||||
|
ethToInputRate: ethToMakerAssetRate,
|
||||||
rfqtIndicativeQuotes,
|
rfqtIndicativeQuotes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -388,6 +413,7 @@ export class MarketOperationUtils {
|
|||||||
const batchOrderFillableAmounts = executeResults.splice(0, batchNativeOrders.length) as BigNumber[][];
|
const batchOrderFillableAmounts = executeResults.splice(0, batchNativeOrders.length) as BigNumber[][];
|
||||||
const batchEthToTakerAssetRate = executeResults.splice(0, batchNativeOrders.length) as BigNumber[];
|
const batchEthToTakerAssetRate = executeResults.splice(0, batchNativeOrders.length) as BigNumber[];
|
||||||
const batchDexQuotes = executeResults.splice(0, batchNativeOrders.length) as DexSample[][][];
|
const batchDexQuotes = executeResults.splice(0, batchNativeOrders.length) as DexSample[][][];
|
||||||
|
const ethToInputRate = ZERO_AMOUNT;
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
batchNativeOrders.map(async (nativeOrders, i) => {
|
batchNativeOrders.map(async (nativeOrders, i) => {
|
||||||
@ -408,6 +434,7 @@ export class MarketOperationUtils {
|
|||||||
dexQuotes,
|
dexQuotes,
|
||||||
inputAmount: makerAmount,
|
inputAmount: makerAmount,
|
||||||
ethToOutputRate: ethToTakerAssetRate,
|
ethToOutputRate: ethToTakerAssetRate,
|
||||||
|
ethToInputRate,
|
||||||
rfqtIndicativeQuotes: [],
|
rfqtIndicativeQuotes: [],
|
||||||
inputToken: makerToken,
|
inputToken: makerToken,
|
||||||
outputToken: takerToken,
|
outputToken: takerToken,
|
||||||
@ -454,6 +481,7 @@ export class MarketOperationUtils {
|
|||||||
rfqtIndicativeQuotes,
|
rfqtIndicativeQuotes,
|
||||||
dexQuotes,
|
dexQuotes,
|
||||||
ethToOutputRate,
|
ethToOutputRate,
|
||||||
|
ethToInputRate,
|
||||||
} = marketSideLiquidity;
|
} = marketSideLiquidity;
|
||||||
const maxFallbackSlippage = opts.maxFallbackSlippage || 0;
|
const maxFallbackSlippage = opts.maxFallbackSlippage || 0;
|
||||||
// Convert native orders and dex quotes into fill paths.
|
// Convert native orders and dex quotes into fill paths.
|
||||||
@ -467,6 +495,7 @@ export class MarketOperationUtils {
|
|||||||
dexQuotes,
|
dexQuotes,
|
||||||
targetInput: inputAmount,
|
targetInput: inputAmount,
|
||||||
ethToOutputRate,
|
ethToOutputRate,
|
||||||
|
ethToInputRate,
|
||||||
excludedSources: opts.excludedSources,
|
excludedSources: opts.excludedSources,
|
||||||
feeSchedule: opts.feeSchedule,
|
feeSchedule: opts.feeSchedule,
|
||||||
});
|
});
|
||||||
|
@ -291,5 +291,6 @@ export interface MarketSideLiquidity {
|
|||||||
nativeOrders: SignedOrder[];
|
nativeOrders: SignedOrder[];
|
||||||
orderFillableAmounts: BigNumber[];
|
orderFillableAmounts: BigNumber[];
|
||||||
ethToOutputRate: BigNumber;
|
ethToOutputRate: BigNumber;
|
||||||
|
ethToInputRate: BigNumber;
|
||||||
rfqtIndicativeQuotes: RFQTIndicativeQuote[];
|
rfqtIndicativeQuotes: RFQTIndicativeQuote[];
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user