get rfq working
This commit is contained in:
@@ -51,18 +51,6 @@ export interface SignedOrder<T> {
|
||||
export type SignedRfqOrder = SignedOrder<RfqOrderFields>;
|
||||
export type SignedLimitOrder = SignedOrder<LimitOrderFields>;
|
||||
export type SignedNativeOrder = SignedLimitOrder | SignedRfqOrder;
|
||||
export type NativeOrderWithFillableAmounts = SignedNativeOrder & NativeOrderFillableAmountFields;
|
||||
|
||||
/**
|
||||
* fillableMakerAmount: Amount of makerAsset that is fillable
|
||||
* fillableTakerAmount: Amount of takerAsset that is fillable
|
||||
* fillableTakerFeeAmount: Amount of takerFee paid to fill fillableTakerAmount
|
||||
*/
|
||||
export interface NativeOrderFillableAmountFields {
|
||||
fillableMakerAmount: BigNumber;
|
||||
fillableTakerAmount: BigNumber;
|
||||
fillableTakerFeeAmount: BigNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the metadata to call a smart contract with calldata.
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
|
||||
import { MarketOperation, NativeOrderWithFillableAmounts } from '../../types';
|
||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
|
||||
import { MarketOperation } from '../../types';
|
||||
|
||||
import { POSITIVE_INF, SOURCE_FLAGS, ZERO_AMOUNT } from './constants';
|
||||
import { DexSample, Fill } from './types';
|
||||
import { DexSample, ERC20BridgeSource, Fill, GenericBridgeFill, NativeOrderFill } from './types';
|
||||
|
||||
// tslint:disable: prefer-for-of no-bitwise completed-docs
|
||||
|
||||
@@ -93,66 +94,76 @@ export function nativeOrdersToFills(
|
||||
outputAmountPerEth: BigNumber,
|
||||
inputAmountPerEth: BigNumber,
|
||||
gasPrice: BigNumber,
|
||||
): Fill[] {
|
||||
): NativeOrderFill[] {
|
||||
if (orders.length === 0) {
|
||||
return [];
|
||||
}
|
||||
throw new Error(`Not implemented`);
|
||||
// const sourcePathId = hexUtils.random();
|
||||
// // Create a single path from all orders.
|
||||
// let fills: Array<Fill & { adjustedRate: BigNumber }> = [];
|
||||
// for (const o of orders) {
|
||||
// const { fillableTakerAmount, fillableTakerFeeAmount, fillableMakerAmount, type } = o;
|
||||
// const makerAmount = fillableMakerAmount;
|
||||
// const takerAmount = fillableTakerAmount.plus(fillableTakerFeeAmount);
|
||||
// const input = side === MarketOperation.Sell ? takerAmount : makerAmount;
|
||||
// const output = side === MarketOperation.Sell ? makerAmount : takerAmount;
|
||||
// const fee = fees[ERC20BridgeSource.Native] === undefined ? 0 : fees[ERC20BridgeSource.Native]!(o);
|
||||
// const outputPenalty = ethToOutputAmount({
|
||||
// input,
|
||||
// output,
|
||||
// inputAmountPerEth,
|
||||
// outputAmountPerEth,
|
||||
// ethAmount: fee,
|
||||
// });
|
||||
// // targetInput can be less than the order size
|
||||
// // whilst the penalty is constant, it affects the adjusted output
|
||||
// // only up until the target has been exhausted.
|
||||
// // A large order and an order at the exact target should be penalized
|
||||
// // the same.
|
||||
// const clippedInput = BigNumber.min(targetInput, input);
|
||||
// // scale the clipped output inline with the input
|
||||
// const clippedOutput = clippedInput.dividedBy(input).times(output);
|
||||
// const adjustedOutput =
|
||||
// side === MarketOperation.Sell ? clippedOutput.minus(outputPenalty) : clippedOutput.plus(outputPenalty);
|
||||
// const adjustedRate =
|
||||
// side === MarketOperation.Sell ? adjustedOutput.div(clippedInput) : clippedInput.div(adjustedOutput);
|
||||
// // Skip orders with rates that are <= 0.
|
||||
// if (adjustedRate.lte(0)) {
|
||||
// continue;
|
||||
// }
|
||||
// fills.push({
|
||||
// sourcePathId,
|
||||
// adjustedRate,
|
||||
// adjustedOutput,
|
||||
// input: clippedInput,
|
||||
// output: clippedOutput,
|
||||
// flags: SOURCE_FLAGS[type === FillQuoteTransformerOrderType.Rfq ? 'RfqOrder' : 'LimitOrder'],
|
||||
// index: 0, // TBD
|
||||
// parent: undefined, // TBD
|
||||
// source: ERC20BridgeSource.Native,
|
||||
// type,
|
||||
// fillData: { ...o },
|
||||
// });
|
||||
// }
|
||||
// // Sort by descending adjusted rate.
|
||||
// fills = fills.sort((a, b) => b.adjustedRate.comparedTo(a.adjustedRate));
|
||||
// // Re-index fills.
|
||||
// for (let i = 0; i < fills.length; ++i) {
|
||||
// fills[i].parent = i === 0 ? undefined : fills[i - 1];
|
||||
// fills[i].index = i;
|
||||
// }
|
||||
// return fills;
|
||||
const sourcePathId = hexUtils.random();
|
||||
// Create a single path from all orders.
|
||||
let fills: Array<NativeOrderFill & { adjustedRate: BigNumber }> = [];
|
||||
for (const o of orders) {
|
||||
const { fillableTakerAmount, fillableMakerAmount, type } = o;
|
||||
// TODO(lawrence): handle taker fees.
|
||||
if (o.fillableTakerFeeAmount.gt(0)) {
|
||||
continue;
|
||||
}
|
||||
let input, output;
|
||||
if (side === MarketOperation.Sell) {
|
||||
input = fillableTakerAmount;
|
||||
output = fillableMakerAmount;
|
||||
} else {
|
||||
input = fillableMakerAmount;
|
||||
output = fillableTakerAmount;
|
||||
}
|
||||
const outputPenalty = ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
ethAmount: gasPrice.times(o.gasCost),
|
||||
});
|
||||
// targetInput can be less than the order size
|
||||
// whilst the penalty is constant, it affects the adjusted output
|
||||
// only up until the target has been exhausted.
|
||||
// A large order and an order at the exact target should be penalized
|
||||
// the same.
|
||||
const clippedInput = BigNumber.min(targetInput, input);
|
||||
// scale the clipped output inline with the input
|
||||
const clippedOutput = clippedInput.dividedBy(input).times(output);
|
||||
const adjustedOutput =
|
||||
side === MarketOperation.Sell ? clippedOutput.minus(outputPenalty) : clippedOutput.plus(outputPenalty);
|
||||
const adjustedRate =
|
||||
side === MarketOperation.Sell ? adjustedOutput.div(clippedInput) : clippedInput.div(adjustedOutput);
|
||||
// Skip orders with rates that are <= 0.
|
||||
if (adjustedRate.lte(0)) {
|
||||
continue;
|
||||
}
|
||||
fills.push({
|
||||
type,
|
||||
sourcePathId,
|
||||
adjustedOutput,
|
||||
adjustedRate,
|
||||
input: clippedInput,
|
||||
output: clippedOutput,
|
||||
flags: SOURCE_FLAGS[type === FillQuoteTransformerOrderType.Rfq ? 'RfqOrder' : 'LimitOrder'],
|
||||
index: 0, // TBD
|
||||
parent: undefined, // TBD
|
||||
source: ERC20BridgeSource.Native,
|
||||
gasCost: o.gasCost,
|
||||
data: {
|
||||
order: o.order,
|
||||
signature: o.signature,
|
||||
},
|
||||
});
|
||||
}
|
||||
// Sort by descending adjusted rate.
|
||||
fills = fills.sort((a, b) => b.adjustedRate.comparedTo(a.adjustedRate));
|
||||
// Re-index fills.
|
||||
for (let i = 0; i < fills.length; ++i) {
|
||||
fills[i].parent = i === 0 ? undefined : fills[i - 1];
|
||||
fills[i].index = i;
|
||||
}
|
||||
return fills;
|
||||
}
|
||||
|
||||
export function dexSamplesToFills(
|
||||
@@ -161,9 +172,9 @@ export function dexSamplesToFills(
|
||||
outputAmountPerEth: BigNumber,
|
||||
inputAmountPerEth: BigNumber,
|
||||
gasPrice: BigNumber,
|
||||
): Fill[] {
|
||||
): GenericBridgeFill[] {
|
||||
const sourcePathId = hexUtils.random();
|
||||
const fills: Fill[] = [];
|
||||
const fills: GenericBridgeFill[] = [];
|
||||
// Drop any non-zero entries. This can occur if the any fills on Kyber were UniswapReserves
|
||||
// We need not worry about Kyber fills going to UniswapReserve as the input amount
|
||||
// we fill is the same as we sampled. I.e we received [0,20,30] output from [1,2,3] input
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { FillQuoteTransformerOrderType, RfqOrder, SignatureType } from '@0x/protocol-utils';
|
||||
import { CommonOrderFields, FillQuoteTransformerOrderType, RfqOrder, SignatureType } from '@0x/protocol-utils';
|
||||
import { V4RFQIndicativeQuote } from '@0x/quote-server';
|
||||
import { BigNumber, NULL_ADDRESS } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
@@ -8,16 +8,11 @@ import {
|
||||
Address,
|
||||
AssetSwapperContractAddresses,
|
||||
MarketOperation,
|
||||
NativeOrderWithFillableAmounts,
|
||||
SignedNativeOrder,
|
||||
SignedRfqOrder,
|
||||
} from '../../types';
|
||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
|
||||
import { QuoteRequestor } from '../quote_requestor';
|
||||
import {
|
||||
getNativeAdjustedFillableAmountsFromMakerAmount,
|
||||
getNativeAdjustedFillableAmountsFromTakerAmount,
|
||||
getNativeAdjustedMakerFillAmount,
|
||||
} from '../utils';
|
||||
|
||||
import {
|
||||
dexSampleToReportSource,
|
||||
@@ -35,13 +30,12 @@ import {
|
||||
FEE_QUOTE_SOURCES_BY_CHAIN_ID,
|
||||
NATIVE_FEE_TOKEN_BY_CHAIN_ID,
|
||||
SELL_SOURCE_FILTER_BY_CHAIN_ID,
|
||||
SOURCE_FLAGS,
|
||||
ZERO_AMOUNT,
|
||||
} from './constants';
|
||||
import { createFills } from './fills';
|
||||
import { getIntermediateTokens } from './multihop_utils';
|
||||
import { Path, PathPenaltyOpts } from './path';
|
||||
import { fillsToSortedPaths, findOptimalPathJSAsync, findOptimalRustPathFromSamples } from './path_optimizer';
|
||||
import { findOptimalPathJSAsync, findOptimalRustPathFromSamples } from './path_optimizer';
|
||||
import { Sampler } from './sampler';
|
||||
import { SourceFilters } from './source_filters';
|
||||
import {
|
||||
@@ -61,6 +55,7 @@ import {
|
||||
} from './types';
|
||||
|
||||
const SHOULD_USE_RUST_ROUTER = process.env.RUST_ROUTER === 'true';
|
||||
const RFQT_ORDER_GAS_COST = Number(process.env.RFQT_ORDER_GAS_COST || 0) || 100e3;
|
||||
|
||||
// tslint:disable:boolean-naming
|
||||
|
||||
@@ -671,6 +666,8 @@ export class MarketOperationUtils {
|
||||
marketSideLiquidity.quotes,
|
||||
side,
|
||||
indicativeQuotes.map(indicativeRfqQuoteToSignedNativeOrder),
|
||||
[],
|
||||
RFQT_ORDER_GAS_COST,
|
||||
);
|
||||
optimizerResult = await this._generateOptimizedOrdersAsync(marketSideLiquidity, optimizerOpts);
|
||||
}
|
||||
@@ -700,7 +697,7 @@ export class MarketOperationUtils {
|
||||
: await rfqt.firmQuoteValidator.getRfqtTakerFillableAmountsAsync(
|
||||
firmQuotes.map(q => new RfqOrder(q.order)),
|
||||
);
|
||||
injectRfqLiquidity(marketSideLiquidity.quotes, side, firmQuotes, rfqTakerFillableAmounts);
|
||||
injectRfqLiquidity(marketSideLiquidity.quotes, side, firmQuotes, rfqTakerFillableAmounts, RFQT_ORDER_GAS_COST);
|
||||
|
||||
// Re-run optimizer with the new firm quote. This is the second and last time
|
||||
// we run the optimized in a block of code. In this case, we don't catch a potential `NoOptimalPath` exception
|
||||
@@ -813,16 +810,6 @@ export class MarketOperationUtils {
|
||||
exchangeProxyOverhead: ExchangeProxyOverhead;
|
||||
runLimit?: number;
|
||||
}): Promise<Path | undefined | null> {
|
||||
const fills = createFills({
|
||||
side: opts.side,
|
||||
orders: opts.nativeOrders,
|
||||
dexQuotes: opts.dexQuotes,
|
||||
targetInput: opts.inputAmount,
|
||||
outputAmountPerEth: opts.outputAmountPerEth,
|
||||
inputAmountPerEth: opts.inputAmountPerEth,
|
||||
gasPrice: opts.gasPrice,
|
||||
});
|
||||
|
||||
// Find the optimal path.
|
||||
const penaltyOpts: PathPenaltyOpts = {
|
||||
outputAmountPerEth: opts.outputAmountPerEth,
|
||||
@@ -843,6 +830,16 @@ export class MarketOperationUtils {
|
||||
this._sampler.chainId,
|
||||
);
|
||||
};
|
||||
|
||||
const fills = createFills({
|
||||
side: opts.side,
|
||||
orders: opts.nativeOrders,
|
||||
dexQuotes: opts.dexQuotes,
|
||||
targetInput: opts.inputAmount,
|
||||
outputAmountPerEth: opts.outputAmountPerEth,
|
||||
inputAmountPerEth: opts.inputAmountPerEth,
|
||||
gasPrice: opts.gasPrice,
|
||||
});
|
||||
return findOptimalPathJSAsync(opts.side, fills, opts.inputAmount, opts.runLimit, penaltyOpts);
|
||||
}
|
||||
|
||||
@@ -1019,6 +1016,7 @@ function injectRfqLiquidity(
|
||||
side: MarketOperation,
|
||||
orders: SignedRfqOrder[],
|
||||
orderFillableTakerAmounts: BigNumber[] = [],
|
||||
gasCostPerOrder: number,
|
||||
): void {
|
||||
if (orders.length === 0) {
|
||||
return;
|
||||
@@ -1027,11 +1025,12 @@ function injectRfqLiquidity(
|
||||
const fullOrders = orders.map((o, i) => ({
|
||||
...o,
|
||||
fillableTakerAmount: orderFillableTakerAmounts[i] || ZERO_AMOUNT,
|
||||
fillableMakerAmount: getNativeAdjustedMakerFillAmount(
|
||||
fillableMakerAmount: getNativeOrderMakerFillAmount(
|
||||
o.order,
|
||||
orderFillableTakerAmounts[i],
|
||||
),
|
||||
fillableTakerFeeAmount: ZERO_AMOUNT,
|
||||
gasCost: gasCostPerOrder,
|
||||
}));
|
||||
const inputToken = side === MarketOperation.Sell ? takerToken : makerToken;
|
||||
const outputToken = side === MarketOperation.Sell ? makerToken : takerToken;
|
||||
@@ -1058,10 +1057,10 @@ function getTakerMakerTokenFromTokenPath(tokenPath: Address[]): [Address, Addres
|
||||
return [tokenPath[0], tokenPath[tokenPath.length - 1]];
|
||||
}
|
||||
|
||||
function getInputOutputTokenFromTokenPath(side: MarketOperation, tokenPath: Address[]): [Address, Address] {
|
||||
const tokens = getTakerMakerTokenFromTokenPath(tokenPath);
|
||||
if (side === MarketOperation.Buy) {
|
||||
tokens.reverse();
|
||||
}
|
||||
return tokens;
|
||||
function getNativeOrderMakerFillAmount(order: CommonOrderFields, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because exchange rate favors Maker
|
||||
return takerFillAmount
|
||||
.multipliedBy(order.makerAmount)
|
||||
.div(order.takerAmount)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@ import { ethToOutputAmount } from './fills';
|
||||
import { createBridgeOrder, createNativeOptimizedOrder } from './orders';
|
||||
import { getCompleteRate, getRate } from './rate_utils';
|
||||
import {
|
||||
BridgeFill,
|
||||
CollapsedGenericBridgeFill,
|
||||
CollapsedFill,
|
||||
CollapsedNativeOrderFill,
|
||||
|
@@ -6,7 +6,8 @@ import * as _ from 'lodash';
|
||||
import { performance } from 'perf_hooks';
|
||||
|
||||
import { DEFAULT_INFO_LOGGER } from '../../constants';
|
||||
import { MarketOperation, NativeOrderWithFillableAmounts } from '../../types';
|
||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
|
||||
import { MarketOperation } from '../../types';
|
||||
import { VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID } from '../market_operation_utils/constants';
|
||||
|
||||
import { dexSamplesToFills, ethToOutputAmount, nativeOrdersToFills } from './fills';
|
||||
@@ -45,7 +46,7 @@ function calculateOuputFee(
|
||||
gasPrice: BigNumber,
|
||||
): BigNumber {
|
||||
if (isDexSample(sampleOrNativeOrder)) {
|
||||
const { input, output, source, encodedFillData } = sampleOrNativeOrder;
|
||||
const { input, output } = sampleOrNativeOrder;
|
||||
const fee = gasPrice.times(sampleOrNativeOrder.gasCost);
|
||||
const outputFee = ethToOutputAmount({
|
||||
input,
|
||||
@@ -56,16 +57,15 @@ function calculateOuputFee(
|
||||
});
|
||||
return outputFee;
|
||||
} else {
|
||||
throw new Error(`No implementado`);
|
||||
// const { input, output } = nativeOrderToNormalizedAmounts(side, sampleOrNativeOrder);
|
||||
// const outputFee = ethToOutputAmount({
|
||||
// input,
|
||||
// output,
|
||||
// inputAmountPerEth,
|
||||
// outputAmountPerEth,
|
||||
// ethAmount: fee,
|
||||
// });
|
||||
// return outputFee;
|
||||
const { input, output } = nativeOrderToNormalizedAmounts(side, sampleOrNativeOrder);
|
||||
const outputFee = ethToOutputAmount({
|
||||
input,
|
||||
output,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth,
|
||||
ethAmount: gasPrice.times((sampleOrNativeOrder as NativeOrderWithFillableAmounts).gasCost),
|
||||
});
|
||||
return outputFee;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ export async function findOptimalPathJSAsync(
|
||||
): Promise<Path | undefined> {
|
||||
// Sort fill arrays by descending adjusted completed rate.
|
||||
// Remove any paths which cannot impact the optimal path
|
||||
const sortedPaths = reducePaths(fillsToSortedPaths(fills, side, targetInput, opts), side);
|
||||
const sortedPaths = reducePaths(fillsToSortedPaths(fills, side, targetInput, opts));
|
||||
if (sortedPaths.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -420,7 +420,7 @@ export function fillsToSortedPaths(
|
||||
}
|
||||
|
||||
// Remove paths which have no impact on the optimal path
|
||||
export function reducePaths(sortedPaths: Path[], side: MarketOperation): Path[] {
|
||||
export function reducePaths(sortedPaths: Path[]): Path[] {
|
||||
// Any path which has a min rate that is less than the best adjusted completed rate has no chance of improving
|
||||
// the overall route.
|
||||
const bestNonNativeCompletePath = sortedPaths.filter(
|
||||
|
@@ -2,11 +2,15 @@ import {
|
||||
FillQuoteTransformerLimitOrderInfo,
|
||||
FillQuoteTransformerOrderType,
|
||||
FillQuoteTransformerRfqOrderInfo,
|
||||
LimitOrderFields,
|
||||
RfqOrderFields,
|
||||
Signature,
|
||||
} from '@0x/protocol-utils';
|
||||
import { MarketOperation } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { Address, Bytes, NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
|
||||
import { Address, Bytes, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
|
||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
|
||||
import { QuoteRequestor } from '../../utils/quote_requestor';
|
||||
import { PriceComparisonsReport, QuoteReport } from '../quote_report_generator';
|
||||
|
||||
@@ -200,8 +204,8 @@ export interface MooniswapFillData extends BridgeFillData {
|
||||
}
|
||||
|
||||
export interface NativeOrderFillData {
|
||||
type: FillQuoteTransformerOrderType.Limit | FillQuoteTransformerOrderType.Rfq;
|
||||
orderInfo: FillQuoteTransformerLimitOrderInfo;
|
||||
order: LimitOrderFields | RfqOrderFields;
|
||||
signature: Signature;
|
||||
}
|
||||
|
||||
/**
|
||||
|
72
packages/asset-swapper/src/utils/native_orders.ts
Normal file
72
packages/asset-swapper/src/utils/native_orders.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import {
|
||||
CommonOrderFields,
|
||||
FillQuoteTransformerOrderType,
|
||||
LimitOrderFields,
|
||||
RfqOrderFields,
|
||||
Signature,
|
||||
} from '@0x/protocol-utils';
|
||||
|
||||
import { SignedNativeOrder } from '../types';
|
||||
|
||||
export interface SignedOrder<T> {
|
||||
order: T;
|
||||
type: FillQuoteTransformerOrderType.Limit | FillQuoteTransformerOrderType.Rfq;
|
||||
signature: Signature;
|
||||
}
|
||||
|
||||
export type NativeOrderWithFillableAmounts = SignedNativeOrder & NativeOrderFillableAmountFields & {
|
||||
gasCost: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* fillableMakerAmount: Amount of makerAsset that is fillable
|
||||
* fillableTakerAmount: Amount of takerAsset that is fillable
|
||||
* fillableTakerFeeAmount: Amount of takerFee paid to fill fillableTakerAmount
|
||||
*/
|
||||
export interface NativeOrderFillableAmountFields {
|
||||
fillableMakerAmount: BigNumber;
|
||||
fillableTakerAmount: BigNumber;
|
||||
fillableTakerFeeAmount: BigNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an amount of taker asset, calculate the the amount of maker asset
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of taker asset
|
||||
*/
|
||||
export function getNativeMakerFillAmount(order: CommonOrderFields, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because exchange rate favors Maker
|
||||
const makerFillAmount = takerFillAmount
|
||||
.multipliedBy(order.makerAmount)
|
||||
.div(order.takerAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return makerFillAmount;
|
||||
}
|
||||
/**
|
||||
* Given an amount of maker asset, calculate the equivalent amount in taker asset
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of maker asset
|
||||
*/
|
||||
export function getNativeTakerFillAmount(order: CommonOrderFields, makerFillAmount: BigNumber): BigNumber {
|
||||
// Round up because exchange rate favors Maker
|
||||
const takerFillAmount = makerFillAmount
|
||||
.multipliedBy(order.takerAmount)
|
||||
.div(order.makerAmount)
|
||||
.integerValue(BigNumber.ROUND_CEIL);
|
||||
return takerFillAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an amount of taker asset, calculate the fee amount required for the taker
|
||||
* @param order The order
|
||||
* @param takerFillAmount the amount of taker asset
|
||||
*/
|
||||
export function getNativeTakerFeeFillAmount(order: LimitOrderFields, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because Taker fee rate favors Taker
|
||||
const takerFeeAmount = takerFillAmount
|
||||
.multipliedBy(order.takerTokenFeeAmount)
|
||||
.div(order.takerAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return takerFeeAmount;
|
||||
}
|
@@ -2,7 +2,7 @@ import { FillQuoteTransformerOrderType, RfqOrderFields, Signature } from '@0x/pr
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import _ = require('lodash');
|
||||
|
||||
import { MarketOperation, NativeOrderWithFillableAmounts } from '../types';
|
||||
import { MarketOperation } from '../types';
|
||||
|
||||
import {
|
||||
CollapsedFill,
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ERC20BridgeSource,
|
||||
CollapsedNativeOrderFill,
|
||||
} from './market_operation_utils/types';
|
||||
import { NativeOrderWithFillableAmounts } from './native_orders';
|
||||
import { QuoteRequestor } from './quote_requestor';
|
||||
|
||||
export interface QuoteReportEntryBase {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
|
||||
import { FillQuoteTransformerOrderType, LimitOrderFields } from '@0x/protocol-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { constants } from '../constants';
|
||||
import { MarketOperation, SwapQuoteLimitOrder, SwapQuoteOrder } from '../types';
|
||||
|
||||
import { getNativeAdjustedTakerFeeAmount } from './utils';
|
||||
import { getNativeTakerFeeFillAmount } from './native_orders';
|
||||
|
||||
const { PROTOCOL_FEE_MULTIPLIER, ZERO_AMOUNT } = constants;
|
||||
const { ROUND_DOWN, ROUND_UP } = BigNumber;
|
||||
@@ -219,8 +219,8 @@ function createBestCaseFillOrderCalls(quoteInfo: QuoteFillInfo): QuoteFillOrderC
|
||||
totalOrderOutput: o.makerAmount,
|
||||
totalOrderInputFee:
|
||||
o.type === FillQuoteTransformerOrderType.Limit
|
||||
? getNativeAdjustedTakerFeeAmount(
|
||||
(o as SwapQuoteLimitOrder).fillData.orderInfo.order,
|
||||
? getNativeTakerFeeFillAmount(
|
||||
((o as SwapQuoteLimitOrder).fillData.order as LimitOrderFields),
|
||||
o.takerAmount,
|
||||
)
|
||||
: ZERO_AMOUNT,
|
||||
|
@@ -1,104 +1,4 @@
|
||||
import { ChainId } from '@0x/contract-addresses';
|
||||
import { CommonOrderFields, FillQuoteTransformerOrderType, LimitOrderFields } from '@0x/protocol-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
|
||||
import { constants } from '../constants';
|
||||
import { NativeOrderFillableAmountFields, SignedNativeOrder } from '../types';
|
||||
|
||||
import { ZERO_AMOUNT } from './market_operation_utils/constants';
|
||||
|
||||
// tslint:disable: no-unnecessary-type-assertion completed-docs
|
||||
|
||||
export function numberPercentageToEtherTokenAmountPercentage(percentage: number): BigNumber {
|
||||
return Web3Wrapper.toBaseUnitAmount(constants.ONE_AMOUNT, constants.ETHER_TOKEN_DECIMALS).multipliedBy(percentage);
|
||||
}
|
||||
|
||||
export function getAdjustedTakerAmountFromFees<T extends LimitOrderFields>(order: T): BigNumber {
|
||||
return order.takerAmount.plus(order.takerTokenFeeAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an amount of taker asset, calculate the the amount of maker asset
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of taker asset
|
||||
*/
|
||||
export function getNativeAdjustedMakerFillAmount(order: CommonOrderFields, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because exchange rate favors Maker
|
||||
const makerFillAmount = takerFillAmount
|
||||
.multipliedBy(order.makerAmount)
|
||||
.div(order.takerAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return makerFillAmount;
|
||||
}
|
||||
/**
|
||||
* Given an amount of maker asset, calculate the equivalent amount in taker asset
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of maker asset
|
||||
*/
|
||||
export function getNativeAdjustedTakerFillAmount(order: CommonOrderFields, makerFillAmount: BigNumber): BigNumber {
|
||||
// Round up because exchange rate favors Maker
|
||||
const takerFillAmount = makerFillAmount
|
||||
.multipliedBy(order.takerAmount)
|
||||
.div(order.makerAmount)
|
||||
.integerValue(BigNumber.ROUND_CEIL);
|
||||
return takerFillAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an amount of taker asset, calculate the fee amount required for the taker
|
||||
* @param order The order
|
||||
* @param takerFillAmount the amount of taker asset
|
||||
*/
|
||||
export function getNativeAdjustedTakerFeeAmount(order: LimitOrderFields, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because Taker fee rate favors Taker
|
||||
const takerFeeAmount = takerFillAmount
|
||||
.multipliedBy(order.takerTokenFeeAmount)
|
||||
.div(order.takerAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return takerFeeAmount;
|
||||
}
|
||||
|
||||
const EMPTY_FILLABLE_AMOUNTS: NativeOrderFillableAmountFields = {
|
||||
fillableMakerAmount: ZERO_AMOUNT,
|
||||
fillableTakerAmount: ZERO_AMOUNT,
|
||||
fillableTakerFeeAmount: ZERO_AMOUNT,
|
||||
};
|
||||
|
||||
export function getNativeAdjustedFillableAmountsFromTakerAmount(
|
||||
order: SignedNativeOrder,
|
||||
takerFillableAmount: BigNumber,
|
||||
): NativeOrderFillableAmountFields {
|
||||
if (takerFillableAmount.isZero()) {
|
||||
return EMPTY_FILLABLE_AMOUNTS;
|
||||
}
|
||||
return {
|
||||
fillableTakerAmount: takerFillableAmount,
|
||||
fillableMakerAmount: getNativeAdjustedMakerFillAmount(order.order, takerFillableAmount),
|
||||
fillableTakerFeeAmount:
|
||||
order.type === FillQuoteTransformerOrderType.Limit
|
||||
? getNativeAdjustedTakerFeeAmount(order.order as LimitOrderFields, takerFillableAmount)
|
||||
: ZERO_AMOUNT,
|
||||
};
|
||||
}
|
||||
|
||||
export function getNativeAdjustedFillableAmountsFromMakerAmount(
|
||||
order: SignedNativeOrder,
|
||||
makerFillableAmount: BigNumber,
|
||||
): NativeOrderFillableAmountFields {
|
||||
if (makerFillableAmount.isZero()) {
|
||||
return EMPTY_FILLABLE_AMOUNTS;
|
||||
}
|
||||
const takerFillableAmount = getNativeAdjustedTakerFillAmount(order.order, makerFillableAmount);
|
||||
return {
|
||||
fillableMakerAmount: makerFillableAmount,
|
||||
fillableTakerAmount: takerFillableAmount,
|
||||
fillableTakerFeeAmount:
|
||||
order.type === FillQuoteTransformerOrderType.Limit
|
||||
? getNativeAdjustedTakerFeeAmount(order.order as LimitOrderFields, takerFillableAmount)
|
||||
: ZERO_AMOUNT,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO(kimpers): Consolidate this implementation with the one in @0x/token-metadata
|
||||
export function valueByChainId<T>(rest: Partial<{ [key in ChainId]: T }>, defaultValue: T): { [key in ChainId]: T } {
|
||||
|
@@ -4,6 +4,7 @@
|
||||
"max-file-line-count": false,
|
||||
"binary-expression-operand-order": false,
|
||||
"no-bitwise": false,
|
||||
"completed-docs": false
|
||||
},
|
||||
"linterOptions": {
|
||||
"exclude": ["src/artifacts.ts", "test/artifacts.ts"]
|
||||
|
Reference in New Issue
Block a user