refactored for market sell + buy

This commit is contained in:
David Sun
2019-06-27 16:54:13 -07:00
parent 1207b68f57
commit 288a7d4cea
4 changed files with 117 additions and 44 deletions

View File

@@ -5,7 +5,6 @@ import {
ForwarderSwapQuoteExecutionOpts,
ForwarderSwapQuoteGetOutputOpts,
OrdersAndFillableAmounts,
SwapQuoteOperation,
SwapQuoteRequestOpts,
SwapQuoterOpts,
} from './types';
@@ -30,7 +29,6 @@ const DEFAULT_FORWARDER_SWAP_QUOTE_EXECUTE_OPTS: ForwarderSwapQuoteExecutionOpts
const DEFAULT_SWAP_QUOTE_REQUEST_OPTS: SwapQuoteRequestOpts = {
shouldForceOrderRefresh: false,
slippagePercentage: 0.2, // 20% slippage protection,
operation: SwapQuoteOperation.MarketBuy,
};
const EMPTY_ORDERS_AND_FILLABLE_AMOUNTS: OrdersAndFillableAmounts = {

View File

@@ -12,13 +12,14 @@ import { StandardRelayerAPIOrderProvider } from './order_providers/standard_rela
import {
LiquidityForAssetData,
LiquidityRequestOpts,
MarketBuySwapQuote,
MarketSellSwapQuote,
OrderProvider,
OrdersAndFillableAmounts,
SwapQuote,
SwapQuoteRequestOpts,
SwapQuoterError,
SwapQuoterOpts,
SwapQuoteOperation,
} from './types';
import { assert } from './utils/assert';
@@ -126,25 +127,25 @@ export class SwapQuoter {
* You can then pass the `SwapQuote` to a `SwapQuoteConsumer` to execute a buy, or process SwapQuote for on-chain consumption.
* @param makerAssetData The makerAssetData of the desired asset to swap for (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param takerAssetData The takerAssetData of the asset to swap makerAssetData for (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param makerAssetSwapAmount The amount of maker asset to swap for.
* @param takerAssetSellAmount The amount of maker asset to swap for.
* @param options Options for the request. See type definition for more information.
*
* @return An object that conforms to SwapQuote that satisfies the request. See type definition for more information.
*/
public async getSwapQuoteAsync(
public async getMarketSellSwapQuoteAsync(
makerAssetData: string,
takerAssetData: string,
assetSwapAmount: BigNumber,
takerAssetSellAmount: BigNumber,
options: Partial<SwapQuoteRequestOpts> = {},
): Promise<SwapQuote> {
const { shouldForceOrderRefresh, slippagePercentage, operation } = _.merge(
): Promise<MarketSellSwapQuote> {
const { shouldForceOrderRefresh, slippagePercentage } = _.merge(
{},
constants.DEFAULT_SWAP_QUOTE_REQUEST_OPTS,
options,
);
assert.isString('makerAssetData', makerAssetData);
assert.isString('takerAssetData', takerAssetData);
assert.isBigNumber('assetSwapAmount', assetSwapAmount);
assert.isBigNumber('takerAssetSellAmount', takerAssetSellAmount);
assert.isBoolean('shouldForceOrderRefresh', shouldForceOrderRefresh);
assert.isNumber('slippagePercentage', slippagePercentage);
const zrxTokenAssetData = this._getZrxTokenAssetDataOrThrow();
@@ -165,24 +166,68 @@ export class SwapQuoter {
}: For makerAssetdata ${makerAssetData} and takerAssetdata ${takerAssetData}`,
);
}
let swapQuote: SwapQuote;
if (operation === SwapQuoteOperation.MarketBuy) {
swapQuote = swapQuoteCalculator.calculateMarketBuySwapQuote(
const swapQuote = swapQuoteCalculator.calculateMarketSellSwapQuote(
ordersAndFillableAmounts,
feeOrdersAndFillableAmounts,
assetSwapAmount,
takerAssetSellAmount,
slippagePercentage,
isMakerAssetZrxToken,
);
} else {
swapQuote = swapQuoteCalculator.calculateMarketSellSwapQuote(
ordersAndFillableAmounts,
feeOrdersAndFillableAmounts,
assetSwapAmount,
slippagePercentage,
isMakerAssetZrxToken,
return swapQuote;
}
/**
* Get a `SwapQuote` containing all information relevant to fulfilling a swap between a desired ERC20 token address and ERC20 owned by a provided address.
* You can then pass the `SwapQuote` to a `SwapQuoteConsumer` to execute a buy, or process SwapQuote for on-chain consumption.
* @param makerAssetData The makerAssetData of the desired asset to swap for (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param takerAssetData The takerAssetData of the asset to swap makerAssetData for (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param makerAssetSwapAmount The amount of maker asset to swap for.
* @param options Options for the request. See type definition for more information.
*
* @return An object that conforms to SwapQuote that satisfies the request. See type definition for more information.
*/
public async getMarketBuySwapQuoteAsync(
makerAssetData: string,
takerAssetData: string,
makerAssetBuyAmount: BigNumber,
options: Partial<SwapQuoteRequestOpts> = {},
): Promise<MarketBuySwapQuote> {
const { shouldForceOrderRefresh, slippagePercentage } = _.merge(
{},
constants.DEFAULT_SWAP_QUOTE_REQUEST_OPTS,
options,
);
assert.isString('makerAssetData', makerAssetData);
assert.isString('takerAssetData', takerAssetData);
assert.isBigNumber('makerAssetBuyAmount', makerAssetBuyAmount);
assert.isBoolean('shouldForceOrderRefresh', shouldForceOrderRefresh);
assert.isNumber('slippagePercentage', slippagePercentage);
const zrxTokenAssetData = this._getZrxTokenAssetDataOrThrow();
const isMakerAssetZrxToken = makerAssetData === zrxTokenAssetData;
// get the relevant orders for the makerAsset and fees
// if the requested assetData is ZRX, don't get the fee info
const [ordersAndFillableAmounts, feeOrdersAndFillableAmounts] = await Promise.all([
this.getOrdersAndFillableAmountsAsync(makerAssetData, takerAssetData, shouldForceOrderRefresh),
isMakerAssetZrxToken
? Promise.resolve(constants.EMPTY_ORDERS_AND_FILLABLE_AMOUNTS)
: this.getOrdersAndFillableAmountsAsync(zrxTokenAssetData, takerAssetData, shouldForceOrderRefresh),
shouldForceOrderRefresh,
]);
if (ordersAndFillableAmounts.orders.length === 0) {
throw new Error(
`${
SwapQuoterError.AssetUnavailable
}: For makerAssetdata ${makerAssetData} and takerAssetdata ${takerAssetData}`,
);
}
const swapQuote = swapQuoteCalculator.calculateMarketBuySwapQuote(
ordersAndFillableAmounts,
feeOrdersAndFillableAmounts,
makerAssetBuyAmount,
slippagePercentage,
isMakerAssetZrxToken,
);
return swapQuote;
}
/**
@@ -195,18 +240,43 @@ export class SwapQuoter {
*
* @return An object that conforms to SwapQuote that satisfies the request. See type definition for more information.
*/
public async getSwapQuoteForERC20TokenAddressAsync(
public async getMarketBuySwapQuoteForERC20TokenAddressAsync(
makerTokenAddress: string,
takerTokenAddress: string,
assetSwapAmount: BigNumber,
makerAssetBuyAmount: BigNumber,
options: Partial<SwapQuoteRequestOpts> = {},
): Promise<SwapQuote> {
assert.isETHAddressHex('makerTokenAddress', makerTokenAddress);
assert.isETHAddressHex('takerTokenAddress', takerTokenAddress);
assert.isBigNumber('assetSwapAmount', assetSwapAmount);
assert.isBigNumber('makerAssetBuyAmount', makerAssetBuyAmount);
const makerAssetData = assetDataUtils.encodeERC20AssetData(makerTokenAddress);
const takerAssetData = assetDataUtils.encodeERC20AssetData(takerTokenAddress);
const swapQuote = this.getSwapQuoteAsync(makerAssetData, takerAssetData, assetSwapAmount, options);
const swapQuote = this.getMarketBuySwapQuoteAsync(makerAssetData, takerAssetData, makerAssetBuyAmount, options);
return swapQuote;
}
/**
* Get a `SwapQuote` containing all information relevant to fulfilling a swap between a desired ERC20 token address and ERC20 owned by a provided address.
* You can then pass the `SwapQuote` to a `SwapQuoteConsumer` to execute a buy, or process SwapQuote for on-chain consumption.
* @param makerAssetData The makerAssetData of the desired asset to swap for (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param takerAssetData The takerAssetData of the asset to swap makerAssetData for (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* @param makerAssetSwapAmount The amount of maker asset to swap for.
* @param options Options for the request. See type definition for more information.
*
* @return An object that conforms to SwapQuote that satisfies the request. See type definition for more information.
*/
public async getMarketSellSwapQuoteForERC20TokenAddressAsync(
makerTokenAddress: string,
takerTokenAddress: string,
takerAssetSellAmount: BigNumber,
options: Partial<SwapQuoteRequestOpts> = {},
): Promise<SwapQuote> {
assert.isETHAddressHex('makerTokenAddress', makerTokenAddress);
assert.isETHAddressHex('takerTokenAddress', takerTokenAddress);
assert.isBigNumber('takerAssetSellAmount', takerAssetSellAmount);
const makerAssetData = assetDataUtils.encodeERC20AssetData(makerTokenAddress);
const takerAssetData = assetDataUtils.encodeERC20AssetData(takerTokenAddress);
const swapQuote = this.getMarketSellSwapQuoteAsync(makerAssetData, takerAssetData, takerAssetSellAmount, options);
return swapQuote;
}
/**

View File

@@ -154,11 +154,6 @@ export interface ForwarderSwapQuoteGetOutputOpts extends SwapQuoteGetOutputOpts
*/
export interface ForwarderSwapQuoteExecutionOpts extends ForwarderSwapQuoteGetOutputOpts, SwapQuoteExecutionOpts {}
export enum SwapQuoteOperation {
MarketSell = 'MARKET_SELL',
MarketBuy = 'MARKET_BUY',
}
/**
* takerAssetData: String that represents a specific taker asset (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
* makerAssetData: String that represents a specific maker asset (for more info: https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
@@ -171,13 +166,22 @@ export enum SwapQuoteOperation {
export interface SwapQuote {
takerAssetData: string;
makerAssetData: string;
takerAssetFillAmount?: BigNumber;
makerAssetFillAmount?: BigNumber;
orders: SignedOrder[];
feeOrders: SignedOrder[];
bestCaseQuoteInfo: SwapQuoteInfo;
worstCaseQuoteInfo: SwapQuoteInfo;
operation: SwapQuoteOperation;
}
export interface MarketSellSwapQuote extends SwapQuote {
takerAssetFillAmount: BigNumber;
bestCaseQuoteInfo: MarketSellSwapQuoteInfo;
worstCaseQuoteInfo: MarketSellSwapQuoteInfo;
}
export interface MarketBuySwapQuote extends SwapQuote {
makerAssetFillAmount: BigNumber;
bestCaseQuoteInfo: MarketBuySwapQuoteInfo;
worstCaseQuoteInfo: MarketBuySwapQuoteInfo;
}
export interface SwapQuoteWithAffiliateFee extends SwapQuote {
@@ -190,12 +194,18 @@ export interface SwapQuoteWithAffiliateFee extends SwapQuote {
* totalEthAmount: The total amount of eth required to complete the buy (filling orders, feeOrders, and paying affiliate fee).
*/
export interface SwapQuoteInfo {
takerTokenAmount: BigNumber;
makerTokenAmount: BigNumber;
feeTakerTokenAmount: BigNumber;
totalTakerTokenAmount: BigNumber;
}
export interface MarketSellSwapQuoteInfo extends SwapQuoteInfo {
makerTokenAmount: BigNumber;
}
export interface MarketBuySwapQuoteInfo extends SwapQuoteInfo {
takerTokenAmount: BigNumber;
}
/**
* shouldForceOrderRefresh: If set to true, new orders and state will be fetched instead of waiting for the next orderRefreshIntervalMs. Defaults to false.
* slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.2 (20%).
@@ -203,7 +213,6 @@ export interface SwapQuoteInfo {
export interface SwapQuoteRequestOpts {
shouldForceOrderRefresh: boolean;
slippagePercentage: number;
operation: SwapQuoteOperation;
}
/*

View File

@@ -4,7 +4,7 @@ import * as _ from 'lodash';
import { constants } from '../constants';
import { InsufficientAssetLiquidityError } from '../errors';
import { OrdersAndFillableAmounts, SwapQuote, SwapQuoteInfo, SwapQuoteOperation, SwapQuoterError } from '../types';
import { MarketBuySwapQuote, MarketBuySwapQuoteInfo, MarketSellSwapQuote, MarketSellSwapQuoteInfo, OrdersAndFillableAmounts, SwapQuoterError } from '../types';
// Calculates a swap quote for orders
export const swapQuoteCalculator = {
@@ -14,7 +14,7 @@ export const swapQuoteCalculator = {
takerAssetFillAmount: BigNumber,
slippagePercentage: number,
isMakerAssetZrxToken: boolean,
): SwapQuote {
): MarketSellSwapQuote {
const orders = ordersAndFillableAmounts.orders;
const remainingFillableMakerAssetAmounts = ordersAndFillableAmounts.remainingFillableMakerAssetAmounts;
const remainingFillableTakerAssetAmounts = remainingFillableMakerAssetAmounts.map((makerAssetAmount: BigNumber, index: number) => {
@@ -112,7 +112,6 @@ export const swapQuoteCalculator = {
feeOrders: resultFeeOrders,
bestCaseQuoteInfo,
worstCaseQuoteInfo,
operation: SwapQuoteOperation.MarketBuy,
};
},
calculateMarketBuySwapQuote(
@@ -121,7 +120,7 @@ export const swapQuoteCalculator = {
makerAssetFillAmount: BigNumber,
slippagePercentage: number,
isMakerAssetZrxToken: boolean,
): SwapQuote {
): MarketBuySwapQuote {
const orders = ordersAndFillableAmounts.orders;
const remainingFillableMakerAssetAmounts = ordersAndFillableAmounts.remainingFillableMakerAssetAmounts;
const feeOrders = feeOrdersAndFillableAmounts.orders;
@@ -213,7 +212,6 @@ export const swapQuoteCalculator = {
feeOrders: resultFeeOrders,
bestCaseQuoteInfo,
worstCaseQuoteInfo,
operation: SwapQuoteOperation.MarketBuy,
};
},
};
@@ -223,7 +221,7 @@ function calculateMarketBuyQuoteInfo(
feeOrdersAndFillableAmounts: OrdersAndFillableAmounts,
makerAssetBuyAmount: BigNumber,
isMakerAssetZrxToken: boolean,
): SwapQuoteInfo {
): MarketBuySwapQuoteInfo {
// find the total eth and zrx needed to buy assetAmount from the resultOrders from left to right
let takerTokenAmount = constants.ZERO_AMOUNT;
let zrxTakerTokenAmount = constants.ZERO_AMOUNT;
@@ -247,7 +245,6 @@ function calculateMarketBuyQuoteInfo(
const totalTakerTokenAmount = takerTokenAmount.plus(feeTakerTokenAmount);
return {
takerTokenAmount,
makerTokenAmount: makerAssetBuyAmount,
feeTakerTokenAmount,
totalTakerTokenAmount,
};
@@ -258,7 +255,7 @@ function calculateMarketSellQuoteInfo(
feeOrdersAndFillableAmounts: OrdersAndFillableAmounts,
takerAssetSellAmount: BigNumber,
isMakerAssetZrxToken: boolean,
): SwapQuoteInfo {
): MarketSellSwapQuoteInfo {
// find the total eth and zrx needed to buy assetAmount from the resultOrders from left to right
let makerTokenAmount = constants.ZERO_AMOUNT;
let zrxTakerTokenAmount = constants.ZERO_AMOUNT;
@@ -281,7 +278,6 @@ function calculateMarketSellQuoteInfo(
// eth amount needed in total is the sum of the amount needed for the asset and the amount needed for fees
const totalTakerTokenAmount = takerAssetSellAmount.plus(feeTakerTokenAmount);
return {
takerTokenAmount: takerAssetSellAmount,
makerTokenAmount,
feeTakerTokenAmount,
totalTakerTokenAmount,