Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Asset-swapper: Fallback orders + refactors #2513

Merged
merged 14 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/asset-swapper/CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@
{
"note": "Add support for private liquidity providers",
"pr": 2505
},
{
"note": "Big refactor of market operation utils",
"pr": 2513
},
{
"note": "Remove `dustFractionThreshold`, `noConflicts` options.",
"pr": 2513
},
{
"note": "Revamp fill optimization algorithm",
"pr": 2513
},
{
"note": "Add fallback orders to quotes via `allowFallback` option.",
"pr": 2513
},
{
"note": "Add `maxFallbackSlippage` option.",
"pr": 2513
}
]
},
Expand Down
49 changes: 3 additions & 46 deletions packages/asset-swapper/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import {
SwapQuoterOpts,
} from './types';

import { constants as marketOperationUtilConstants } from './utils/market_operation_utils/constants';
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
import { DEFAULT_GET_MARKET_ORDERS_OPTS } from './utils/market_operation_utils/constants';

const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
const NULL_BYTES = '0x';
Expand Down Expand Up @@ -43,7 +42,7 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
orderRefreshIntervalMs: 10000, // 10 seconds
},
...DEFAULT_ORDER_PRUNER_OPTS,
samplerGasLimit: 59e6,
samplerGasLimit: 250e6,
dekz marked this conversation as resolved.
Show resolved Hide resolved
};

const DEFAULT_FORWARDER_EXTENSION_CONTRACT_OPTS: ForwarderExtensionContractOpts = {
Expand All @@ -59,48 +58,7 @@ const DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS: SwapQuoteGetOutputOpts = {
const DEFAULT_FORWARDER_SWAP_QUOTE_EXECUTE_OPTS: SwapQuoteExecutionOpts = DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS;

const DEFAULT_SWAP_QUOTE_REQUEST_OPTS: SwapQuoteRequestOpts = {
...{
slippagePercentage: 0.2, // 20% slippage protection,
},
...marketOperationUtilConstants.DEFAULT_GET_MARKET_ORDERS_OPTS,
};

// Mainnet Curve configuration
const DEFAULT_CURVE_OPTS: { [source: string]: { version: number; curveAddress: string; tokens: string[] } } = {
[ERC20BridgeSource.CurveUsdcDai]: {
version: 1,
curveAddress: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56',
tokens: ['0x6b175474e89094c44da98b954eedeac495271d0f', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
},
[ERC20BridgeSource.CurveUsdcDaiUsdt]: {
version: 1,
curveAddress: '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c',
tokens: [
'0x6b175474e89094c44da98b954eedeac495271d0f',
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
'0xdac17f958d2ee523a2206206994597c13d831ec7',
],
},
[ERC20BridgeSource.CurveUsdcDaiUsdtTusd]: {
version: 1,
curveAddress: '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51',
tokens: [
'0x6b175474e89094c44da98b954eedeac495271d0f',
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
'0xdac17f958d2ee523a2206206994597c13d831ec7',
'0x0000000000085d4780b73119b644ae5ecd22b376',
],
},
[ERC20BridgeSource.CurveUsdcDaiUsdtBusd]: {
version: 1,
curveAddress: '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27',
tokens: [
'0x6b175474e89094c44da98b954eedeac495271d0f',
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
'0xdac17f958d2ee523a2206206994597c13d831ec7',
'0x4fabb145d64652a948d72533023f6e7a623c7c53',
],
},
...DEFAULT_GET_MARKET_ORDERS_OPTS,
};

export const constants = {
Expand All @@ -123,5 +81,4 @@ export const constants = {
PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE,
BRIDGE_ASSET_DATA_PREFIX: '0xdc1600f3',
DEFAULT_CURVE_OPTS,
};
26 changes: 5 additions & 21 deletions packages/asset-swapper/src/swap_quoter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
import { assert } from './utils/assert';
import { calculateLiquidity } from './utils/calculate_liquidity';
import { MarketOperationUtils } from './utils/market_operation_utils';
import { dummyOrderUtils } from './utils/market_operation_utils/dummy_order_utils';
import { createDummyOrderForSampler } from './utils/market_operation_utils/orders';
import { DexOrderSampler } from './utils/market_operation_utils/sampler';
import { orderPrunerUtils } from './utils/order_prune_utils';
import { OrderStateUtils } from './utils/order_state_utils';
Expand Down Expand Up @@ -242,11 +242,7 @@ export class SwapQuoter {
): Promise<Array<MarketBuySwapQuote | undefined>> {
makerAssetBuyAmount.map((a, i) => assert.isBigNumber(`makerAssetBuyAmount[${i}]`, a));
let gasPrice: BigNumber;
const { slippagePercentage, ...calculateSwapQuoteOpts } = _.merge(
{},
constants.DEFAULT_SWAP_QUOTE_REQUEST_OPTS,
options,
);
const calculateSwapQuoteOpts = _.merge({}, constants.DEFAULT_SWAP_QUOTE_REQUEST_OPTS, options);
if (!!options.gasPrice) {
gasPrice = options.gasPrice;
assert.isBigNumber('gasPrice', gasPrice);
Expand All @@ -264,7 +260,7 @@ export class SwapQuoter {
);
if (prunedOrders.length === 0) {
return [
dummyOrderUtils.createDummyOrderForSampler(
createDummyOrderForSampler(
makerAssetDatas[i],
takerAssetData,
this._contractAddresses.uniswapBridge,
Expand All @@ -278,7 +274,6 @@ export class SwapQuoter {
const swapQuotes = await this._swapQuoteCalculator.calculateBatchMarketBuySwapQuoteAsync(
allPrunedOrders,
makerAssetBuyAmount,
slippagePercentage,
gasPrice,
calculateSwapQuoteOpts,
);
Expand Down Expand Up @@ -517,14 +512,9 @@ export class SwapQuoter {
marketOperation: MarketOperation,
options: Partial<SwapQuoteRequestOpts>,
): Promise<SwapQuote> {
const { slippagePercentage, ...calculateSwapQuoteOpts } = _.merge(
{},
constants.DEFAULT_SWAP_QUOTE_REQUEST_OPTS,
options,
);
const calculateSwapQuoteOpts = _.merge({}, constants.DEFAULT_SWAP_QUOTE_REQUEST_OPTS, options);
assert.isString('makerAssetData', makerAssetData);
assert.isString('takerAssetData', takerAssetData);
assert.isNumber('slippagePercentage', slippagePercentage);
let gasPrice: BigNumber;
if (!!options.gasPrice) {
gasPrice = options.gasPrice;
Expand All @@ -537,11 +527,7 @@ export class SwapQuoter {
// if no native orders, pass in a dummy order for the sampler to have required metadata for sampling
if (prunedOrders.length === 0) {
prunedOrders = [
dummyOrderUtils.createDummyOrderForSampler(
makerAssetData,
takerAssetData,
this._contractAddresses.uniswapBridge,
),
createDummyOrderForSampler(makerAssetData, takerAssetData, this._contractAddresses.uniswapBridge),
];
}

Expand All @@ -551,15 +537,13 @@ export class SwapQuoter {
swapQuote = await this._swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
prunedOrders,
assetFillAmount,
slippagePercentage,
gasPrice,
calculateSwapQuoteOpts,
);
} else {
swapQuote = await this._swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
prunedOrders,
assetFillAmount,
slippagePercentage,
gasPrice,
calculateSwapQuoteOpts,
);
Expand Down
4 changes: 2 additions & 2 deletions packages/asset-swapper/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,15 @@ export interface MarketBuySwapQuote extends SwapQuoteBase {
* totalTakerAssetAmount: The total amount of takerAsset required to complete the swap (filling orders, and paying takerFees).
* makerAssetAmount: The amount of makerAsset that will be acquired through the swap.
* protocolFeeInWeiAmount: The amount of ETH to pay (in WEI) as protocol fee to perform the swap for desired asset.
* gas: Amount of estimated gas needed to fill the quote.
*/
export interface SwapQuoteInfo {
feeTakerAssetAmount: BigNumber;
takerAssetAmount: BigNumber;
totalTakerAssetAmount: BigNumber;
makerAssetAmount: BigNumber;
protocolFeeInWeiAmount: BigNumber;
gas: number;
}

/**
Expand All @@ -186,11 +188,9 @@ export interface SwapQuoteOrdersBreakdown {
}

/**
* slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.2 (20%).
* gasPrice: gas price to determine protocolFee amount, default to ethGasStation fast amount
*/
export interface SwapQuoteRequestOpts extends CalculateSwapQuoteOpts {
slippagePercentage: number;
gasPrice?: BigNumber;
}

Expand Down
18 changes: 12 additions & 6 deletions packages/asset-swapper/src/utils/assert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import * as _ from 'lodash';

import { MarketOperation, OrderProviderRequest, SwapQuote, SwapQuoteInfo } from '../types';

import { utils } from './utils';
import {
isAssetDataEquivalent,
isExactAssetData,
isOrderTakerFeePayableWithMakerAsset,
isOrderTakerFeePayableWithTakerAsset,
} from './utils';

export const assert = {
...sharedAssert,
Expand Down Expand Up @@ -36,13 +41,13 @@ export const assert = {
): void {
_.every(orders, (order: SignedOrder, index: number) => {
assert.assert(
utils.isAssetDataEquivalent(takerAssetData, order.takerAssetData),
isAssetDataEquivalent(takerAssetData, order.takerAssetData),
`Expected ${variableName}[${index}].takerAssetData to be ${takerAssetData} but found ${
order.takerAssetData
}`,
);
assert.assert(
utils.isAssetDataEquivalent(makerAssetData, order.makerAssetData),
isAssetDataEquivalent(makerAssetData, order.makerAssetData),
`Expected ${variableName}[${index}].makerAssetData to be ${makerAssetData} but found ${
order.makerAssetData
}`,
Expand All @@ -53,8 +58,8 @@ export const assert = {
_.every(orders, (order: T, index: number) => {
assert.assert(
order.takerFee.isZero() ||
utils.isOrderTakerFeePayableWithTakerAsset(order) ||
utils.isOrderTakerFeePayableWithMakerAsset(order),
isOrderTakerFeePayableWithTakerAsset(order) ||
isOrderTakerFeePayableWithMakerAsset(order),
`Expected ${variableName}[${index}].takerFeeAssetData to be ${order.makerAssetData} or ${
order.takerAssetData
} but found ${order.takerFeeAssetData}`,
Expand All @@ -72,11 +77,12 @@ export const assert = {
},
isValidForwarderSignedOrder(variableName: string, order: SignedOrder, wethAssetData: string): void {
assert.assert(
utils.isExactAssetData(order.takerAssetData, wethAssetData),
isExactAssetData(order.takerAssetData, wethAssetData),
`Expected ${variableName} to have takerAssetData set as ${wethAssetData}, but is ${order.takerAssetData}`,
);
},
isValidSwapQuoteInfo(variableName: string, swapQuoteInfo: SwapQuoteInfo): void {
sharedAssert.isNumber(`${variableName}.gas`, swapQuoteInfo.gas);
sharedAssert.isBigNumber(`${variableName}.feeTakerAssetAmount`, swapQuoteInfo.feeTakerAssetAmount);
sharedAssert.isBigNumber(`${variableName}.totalTakerAssetAmount`, swapQuoteInfo.totalTakerAssetAmount);
sharedAssert.isBigNumber(`${variableName}.takerAssetAmount`, swapQuoteInfo.takerAssetAmount);
Expand Down
6 changes: 3 additions & 3 deletions packages/asset-swapper/src/utils/calculate_liquidity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { BigNumber } from '@0x/utils';

import { LiquidityForTakerMakerAssetDataPair, SignedOrderWithFillableAmounts } from '../types';

import { utils } from './utils';
import { isOrderTakerFeePayableWithMakerAsset, isOrderTakerFeePayableWithTakerAsset } from './utils';

export const calculateLiquidity = (
prunedOrders: SignedOrderWithFillableAmounts[],
): LiquidityForTakerMakerAssetDataPair => {
const liquidityInBigNumbers = prunedOrders.reduce(
(acc, order) => {
const fillableMakerAssetAmount = utils.isOrderTakerFeePayableWithMakerAsset(order)
const fillableMakerAssetAmount = isOrderTakerFeePayableWithMakerAsset(order)
? order.fillableMakerAssetAmount.minus(order.fillableTakerFeeAmount)
: order.fillableMakerAssetAmount;
const fillableTakerAssetAmount = utils.isOrderTakerFeePayableWithTakerAsset(order)
const fillableTakerAssetAmount = isOrderTakerFeePayableWithTakerAsset(order)
? order.fillableTakerAssetAmount.plus(order.fillableTakerFeeAmount)
: order.fillableTakerAssetAmount;
return {
Expand Down
6 changes: 3 additions & 3 deletions packages/asset-swapper/src/utils/fillable_amounts_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import * as _ from 'lodash';

import { SignedOrderWithFillableAmounts } from '../types';

import { utils } from './utils';
import { isOrderTakerFeePayableWithMakerAsset, isOrderTakerFeePayableWithTakerAsset } from './utils';

export const fillableAmountsUtils = {
getTakerAssetAmountSwappedAfterOrderFees(order: SignedOrderWithFillableAmounts): BigNumber {
if (utils.isOrderTakerFeePayableWithTakerAsset(order)) {
if (isOrderTakerFeePayableWithTakerAsset(order)) {
return order.fillableTakerAssetAmount.plus(order.fillableTakerFeeAmount);
} else {
return order.fillableTakerAssetAmount;
}
},
getMakerAssetAmountSwappedAfterOrderFees(order: SignedOrderWithFillableAmounts): BigNumber {
if (utils.isOrderTakerFeePayableWithMakerAsset(order)) {
if (isOrderTakerFeePayableWithMakerAsset(order)) {
return order.fillableMakerAssetAmount.minus(order.fillableTakerFeeAmount);
} else {
return order.fillableMakerAssetAmount;
Expand Down
Loading