refactored types and market sell operation

This commit is contained in:
David Sun
2019-07-03 14:29:28 -07:00
parent d0ea74e180
commit b4ac6d3439
9 changed files with 386 additions and 511 deletions

View File

@@ -10,6 +10,7 @@ import {
FindFeeOrdersThatCoverFeesForTargetOrdersOpts,
FindOrdersThatCoverMakerAssetFillAmountOpts,
FindOrdersThatCoverTakerAssetFillAmountOpts,
MarketOperation,
OrdersAndRemainingMakerFillAmount,
OrdersAndRemainingTakerFillAmount,
} from './types';
@@ -20,60 +21,12 @@ export const marketUtils = {
takerAssetFillAmount: BigNumber,
opts?: FindOrdersThatCoverTakerAssetFillAmountOpts,
): OrdersAndRemainingTakerFillAmount<T> {
assert.doesConformToSchema('orders', orders, schemas.ordersSchema);
assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount);
// try to get remainingFillableTakerAssetAmounts from opts, if it's not there, use takerAssetAmount values from orders
const remainingFillableTakerAssetAmounts = _.get(
opts,
'remainingFillableTakerAssetAmounts',
_.map(orders, order => order.takerAssetAmount),
) as BigNumber[];
_.forEach(remainingFillableTakerAssetAmounts, (amount, index) =>
assert.isValidBaseUnitAmount(`remainingFillableTakerAssetAmount[${index}]`, amount),
);
assert.assert(
orders.length === remainingFillableTakerAssetAmounts.length,
'Expected orders.length to equal opts.remainingFillableMakerAssetAmounts.length',
);
// try to get slippageBufferAmount from opts, if it's not there, default to 0
const slippageBufferAmount = _.get(opts, 'slippageBufferAmount', constants.ZERO_AMOUNT) as BigNumber;
assert.isValidBaseUnitAmount('opts.slippageBufferAmount', slippageBufferAmount);
// calculate total amount of makerAsset needed to be filled
const totalFillAmount = takerAssetFillAmount.plus(slippageBufferAmount);
// iterate through the orders input from left to right until we have enough makerAsset to fill totalFillAmount
const result = _.reduce(
return findOrdersThatCoverAssetFillAmount(
orders,
({ resultOrders, remainingFillAmount, ordersRemainingFillableTakerAssetAmounts }, order, index) => {
if (remainingFillAmount.isLessThanOrEqualTo(constants.ZERO_AMOUNT)) {
return {
resultOrders,
remainingFillAmount: constants.ZERO_AMOUNT,
ordersRemainingFillableTakerAssetAmounts,
};
} else {
const takerAssetAmountAvailable = remainingFillableTakerAssetAmounts[index];
const shouldIncludeOrder = takerAssetAmountAvailable.gt(constants.ZERO_AMOUNT);
// if there is no makerAssetAmountAvailable do not append order to resultOrders
// if we have exceeded the total amount we want to fill set remainingFillAmount to 0
return {
resultOrders: shouldIncludeOrder ? _.concat(resultOrders, order) : resultOrders,
ordersRemainingFillableTakerAssetAmounts: shouldIncludeOrder
? _.concat(ordersRemainingFillableTakerAssetAmounts, takerAssetAmountAvailable)
: ordersRemainingFillableTakerAssetAmounts,
remainingFillAmount: BigNumber.max(
constants.ZERO_AMOUNT,
remainingFillAmount.minus(takerAssetAmountAvailable),
),
};
}
},
{
resultOrders: [] as T[],
remainingFillAmount: totalFillAmount,
ordersRemainingFillableTakerAssetAmounts: [] as BigNumber[],
},
);
return result;
takerAssetFillAmount,
'marketSell',
opts,
) as OrdersAndRemainingTakerFillAmount<T>;
},
/**
* Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount
@@ -90,60 +43,12 @@ export const marketUtils = {
makerAssetFillAmount: BigNumber,
opts?: FindOrdersThatCoverMakerAssetFillAmountOpts,
): OrdersAndRemainingMakerFillAmount<T> {
assert.doesConformToSchema('orders', orders, schemas.ordersSchema);
assert.isValidBaseUnitAmount('makerAssetFillAmount', makerAssetFillAmount);
// try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from orders
const remainingFillableMakerAssetAmounts = _.get(
opts,
'remainingFillableMakerAssetAmounts',
_.map(orders, order => order.makerAssetAmount),
) as BigNumber[];
_.forEach(remainingFillableMakerAssetAmounts, (amount, index) =>
assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount),
);
assert.assert(
orders.length === remainingFillableMakerAssetAmounts.length,
'Expected orders.length to equal opts.remainingFillableMakerAssetAmounts.length',
);
// try to get slippageBufferAmount from opts, if it's not there, default to 0
const slippageBufferAmount = _.get(opts, 'slippageBufferAmount', constants.ZERO_AMOUNT) as BigNumber;
assert.isValidBaseUnitAmount('opts.slippageBufferAmount', slippageBufferAmount);
// calculate total amount of makerAsset needed to be filled
const totalFillAmount = makerAssetFillAmount.plus(slippageBufferAmount);
// iterate through the orders input from left to right until we have enough makerAsset to fill totalFillAmount
const result = _.reduce(
return findOrdersThatCoverAssetFillAmount(
orders,
({ resultOrders, remainingFillAmount, ordersRemainingFillableMakerAssetAmounts }, order, index) => {
if (remainingFillAmount.isLessThanOrEqualTo(constants.ZERO_AMOUNT)) {
return {
resultOrders,
remainingFillAmount: constants.ZERO_AMOUNT,
ordersRemainingFillableMakerAssetAmounts,
};
} else {
const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index];
const shouldIncludeOrder = makerAssetAmountAvailable.gt(constants.ZERO_AMOUNT);
// if there is no makerAssetAmountAvailable do not append order to resultOrders
// if we have exceeded the total amount we want to fill set remainingFillAmount to 0
return {
resultOrders: shouldIncludeOrder ? _.concat(resultOrders, order) : resultOrders,
ordersRemainingFillableMakerAssetAmounts: shouldIncludeOrder
? _.concat(ordersRemainingFillableMakerAssetAmounts, makerAssetAmountAvailable)
: ordersRemainingFillableMakerAssetAmounts,
remainingFillAmount: BigNumber.max(
constants.ZERO_AMOUNT,
remainingFillAmount.minus(makerAssetAmountAvailable),
),
};
}
},
{
resultOrders: [] as T[],
remainingFillAmount: totalFillAmount,
ordersRemainingFillableMakerAssetAmounts: [] as BigNumber[],
},
);
return result;
makerAssetFillAmount,
'marketBuy',
opts,
) as OrdersAndRemainingMakerFillAmount<T>;
},
/**
* Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX
@@ -222,3 +127,82 @@ export const marketUtils = {
// https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarding-contract-specification.md#over-buying-zrx
},
};
function findOrdersThatCoverAssetFillAmount<T extends Order>(
orders: T[],
assetFillAmount: BigNumber,
operation: MarketOperation,
opts?: FindOrdersThatCoverTakerAssetFillAmountOpts,
): OrdersAndRemainingTakerFillAmount<T> | OrdersAndRemainingMakerFillAmount<T> {
const variablePrefix = operation === 'marketBuy' ? 'maker' : 'taker';
assert.doesConformToSchema('orders', orders, schemas.ordersSchema);
assert.isValidBaseUnitAmount(`${variablePrefix}AssetFillAmount}`, assetFillAmount);
// try to get remainingFillableTakerAssetAmounts from opts, if it's not there, use takerAssetAmount values from orders
const remainingFillableAssetAmounts = _.get(
opts,
`remainingFillable${variablePrefix}AssetAmounts`,
_.map(orders, order => (operation === 'marketBuy' ? order.makerAssetAmount : order.takerAssetAmount)),
) as BigNumber[];
_.forEach(remainingFillableAssetAmounts, (amount, index) =>
assert.isValidBaseUnitAmount(`remainingFillable${variablePrefix}AssetAmount[${index}]`, amount),
);
assert.assert(
orders.length === remainingFillableAssetAmounts.length,
`Expected orders.length to equal opts.remainingFillable${variablePrefix}AssetAmounts.length`,
);
// try to get slippageBufferAmount from opts, if it's not there, default to 0
const slippageBufferAmount = _.get(opts, 'slippageBufferAmount', constants.ZERO_AMOUNT) as BigNumber;
assert.isValidBaseUnitAmount('opts.slippageBufferAmount', slippageBufferAmount);
// calculate total amount of asset needed to be filled
const totalFillAmount = assetFillAmount.plus(slippageBufferAmount);
// iterate through the orders input from left to right until we have enough makerAsset to fill totalFillAmount
const result = _.reduce(
orders,
({ resultOrders, remainingFillAmount, ordersRemainingFillableAssetAmounts }, order, index) => {
if (remainingFillAmount.isLessThanOrEqualTo(constants.ZERO_AMOUNT)) {
return {
resultOrders,
remainingFillAmount: constants.ZERO_AMOUNT,
ordersRemainingFillableAssetAmounts,
};
} else {
const assetAmountAvailable = remainingFillableAssetAmounts[index];
const shouldIncludeOrder = assetAmountAvailable.gt(constants.ZERO_AMOUNT);
// if there is no assetAmountAvailable do not append order to resultOrders
// if we have exceeded the total amount we want to fill set remainingFillAmount to 0
return {
resultOrders: shouldIncludeOrder ? _.concat(resultOrders, order) : resultOrders,
ordersRemainingFillableAssetAmounts: shouldIncludeOrder
? _.concat(ordersRemainingFillableAssetAmounts, assetAmountAvailable)
: ordersRemainingFillableAssetAmounts,
remainingFillAmount: BigNumber.max(
constants.ZERO_AMOUNT,
remainingFillAmount.minus(assetAmountAvailable),
),
};
}
},
{
resultOrders: [] as T[],
remainingFillAmount: totalFillAmount,
ordersRemainingFillableAssetAmounts: [] as BigNumber[],
},
);
const {
ordersRemainingFillableAssetAmounts: resultOrdersRemainingFillableAssetAmounts,
...ordersAndRemainingFillAmount
} = result;
if (operation === 'marketBuy') {
return {
...ordersAndRemainingFillAmount,
ordersRemainingFillableMakerAssetAmounts: resultOrdersRemainingFillableAssetAmounts,
};
} else {
return {
...ordersAndRemainingFillAmount,
ordersRemainingFillableMakerAssetAmounts: resultOrdersRemainingFillableAssetAmounts,
};
}
}

View File

@@ -49,6 +49,8 @@ export interface FindOrdersThatCoverTakerAssetFillAmountOpts {
slippageBufferAmount?: BigNumber;
}
export type MarketOperation = 'marketSell' | 'marketBuy';
/**
* remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter.
* You can use `OrderStateUtils` `@0x/order-utils` to perform blockchain lookups for these values.