aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/src/market_utils.ts
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-08-14 04:01:32 +0800
committerFabio Berger <me@fabioberger.com>2018-08-14 04:01:32 +0800
commit9d3c287918389d07f884245bd1bc968955768b6f (patch)
tree460fded537c7d64154972b7d14332f88554d14c0 /packages/order-utils/src/market_utils.ts
parentc2b5fe3d844d35966c5498326000bd8317fb547c (diff)
parent15e15f994a1b18cf2e9be151194c826d53a01601 (diff)
downloaddexon-sol-tools-9d3c287918389d07f884245bd1bc968955768b6f.tar
dexon-sol-tools-9d3c287918389d07f884245bd1bc968955768b6f.tar.gz
dexon-sol-tools-9d3c287918389d07f884245bd1bc968955768b6f.tar.bz2
dexon-sol-tools-9d3c287918389d07f884245bd1bc968955768b6f.tar.lz
dexon-sol-tools-9d3c287918389d07f884245bd1bc968955768b6f.tar.xz
dexon-sol-tools-9d3c287918389d07f884245bd1bc968955768b6f.tar.zst
dexon-sol-tools-9d3c287918389d07f884245bd1bc968955768b6f.zip
Merge branch 'sol-cov-fixes' of github.com:0xProject/0x-monorepo into sol-cov-fixes
* 'sol-cov-fixes' of github.com:0xProject/0x-monorepo: (49 commits) Add @return comments Import marshaller directly Update comment about ethers checksummed address behavior Add packages/coverage/.gitkeep file Update CI config and package.json to run @0xproject/utils tests on CI Update remaining CHANGELOG.json files Change amir picture Update CHANGELOG.json for contract-wrappers Update ethers typings for TypeScript 2.9.2 Update CHANGELOG.json for base-contract Move some ethers-related types to typescript-typings/ethers Apply prettier Add strictArgumentEncodingCheck to BaseContract and use it in contract templates fix(monorepo-scripts): Fix typo in git tag command feat(monorepo-scripts): Add confirmation prompt before publishing fix comments and styling for MixinSignatureValidator Update TypeScript to version 2.9.2 Use asm for hashEIP712Message, increment free memory pointer after asm hashing functions Fix comments, styling, and optimize hashOrder Remove assertion comments ...
Diffstat (limited to 'packages/order-utils/src/market_utils.ts')
-rw-r--r--packages/order-utils/src/market_utils.ts133
1 files changed, 133 insertions, 0 deletions
diff --git a/packages/order-utils/src/market_utils.ts b/packages/order-utils/src/market_utils.ts
new file mode 100644
index 000000000..681059ddf
--- /dev/null
+++ b/packages/order-utils/src/market_utils.ts
@@ -0,0 +1,133 @@
+import { schemas } from '@0xproject/json-schemas';
+import { SignedOrder } from '@0xproject/types';
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+
+import { assert } from './assert';
+import { constants } from './constants';
+
+export const marketUtils = {
+ /**
+ * Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount (taking into account on-chain balances,
+ * allowances, and partial fills) in order to fill the input makerAssetFillAmount plus slippageBufferAmount. Iterates from first order to last.
+ * Sort the input by ascending rate in order to get the subset of orders that will cost the least ETH.
+ * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders should specify the same makerAsset.
+ * All orders should specify WETH as the takerAsset.
+ * @param remainingFillableMakerAssetAmounts An array of BigNumbers corresponding to the signedOrders parameter.
+ * You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups
+ * for these values.
+ * @param makerAssetFillAmount The amount of makerAsset desired to be filled.
+ * @param slippageBufferAmount An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills.
+ * @return Resulting orders and remaining fill amount that could not be covered by the input.
+ */
+ findOrdersThatCoverMakerAssetFillAmount(
+ signedOrders: SignedOrder[],
+ remainingFillableMakerAssetAmounts: BigNumber[],
+ makerAssetFillAmount: BigNumber,
+ slippageBufferAmount: BigNumber = constants.ZERO_AMOUNT,
+ ): { resultOrders: SignedOrder[]; remainingFillAmount: BigNumber } {
+ assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
+ _.forEach(remainingFillableMakerAssetAmounts, (amount, index) =>
+ assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount),
+ );
+ assert.isValidBaseUnitAmount('makerAssetFillAmount', makerAssetFillAmount);
+ assert.isValidBaseUnitAmount('slippageBufferAmount', slippageBufferAmount);
+ assert.assert(
+ signedOrders.length === remainingFillableMakerAssetAmounts.length,
+ 'Expected signedOrders.length to equal remainingFillableMakerAssetAmounts.length',
+ );
+ // calculate total amount of makerAsset needed to be filled
+ const totalFillAmount = makerAssetFillAmount.plus(slippageBufferAmount);
+ // iterate through the signedOrders input from left to right until we have enough makerAsset to fill totalFillAmount
+ const result = _.reduce(
+ signedOrders,
+ ({ resultOrders, remainingFillAmount }, order, index) => {
+ if (remainingFillAmount.lessThanOrEqualTo(constants.ZERO_AMOUNT)) {
+ return { resultOrders, remainingFillAmount: constants.ZERO_AMOUNT };
+ } else {
+ const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index];
+ // 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: makerAssetAmountAvailable.gt(constants.ZERO_AMOUNT)
+ ? _.concat(resultOrders, order)
+ : resultOrders,
+ remainingFillAmount: BigNumber.max(
+ constants.ZERO_AMOUNT,
+ remainingFillAmount.minus(makerAssetAmountAvailable),
+ ),
+ };
+ }
+ },
+ { resultOrders: [] as SignedOrder[], remainingFillAmount: totalFillAmount },
+ );
+ return result;
+ },
+ /**
+ * Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX (taking into account
+ * on-chain balances, allowances, and partial fills) in order to fill the takerFees required by signedOrders plus a
+ * slippageBufferAmount. Iterates from first feeOrder to last. Sort the feeOrders by ascending rate in order to get the subset of
+ * feeOrders that will cost the least ETH.
+ * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders should specify ZRX as
+ * the makerAsset and WETH as the takerAsset.
+ * @param remainingFillableMakerAssetAmounts An array of BigNumbers corresponding to the signedOrders parameter.
+ * You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups
+ * for these values.
+ * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders should specify ZRX as
+ * the makerAsset and WETH as the takerAsset.
+ * @param remainingFillableFeeAmounts An array of BigNumbers corresponding to the signedFeeOrders parameter.
+ * You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups
+ * for these values.
+ * @param slippageBufferAmount An additional amount of fee to be covered by the result in case of trade collisions or partial fills.
+ * @return Resulting orders and remaining fee amount that could not be covered by the input.
+ */
+ findFeeOrdersThatCoverFeesForTargetOrders(
+ signedOrders: SignedOrder[],
+ remainingFillableMakerAssetAmounts: BigNumber[],
+ signedFeeOrders: SignedOrder[],
+ remainingFillableFeeAmounts: BigNumber[],
+ slippageBufferAmount: BigNumber = constants.ZERO_AMOUNT,
+ ): { resultOrders: SignedOrder[]; remainingFeeAmount: BigNumber } {
+ assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
+ _.forEach(remainingFillableMakerAssetAmounts, (amount, index) =>
+ assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount),
+ );
+ assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
+ _.forEach(remainingFillableFeeAmounts, (amount, index) =>
+ assert.isValidBaseUnitAmount(`remainingFillableFeeAmounts[${index}]`, amount),
+ );
+ assert.isValidBaseUnitAmount('slippageBufferAmount', slippageBufferAmount);
+ assert.assert(
+ signedOrders.length === remainingFillableMakerAssetAmounts.length,
+ 'Expected signedOrders.length to equal remainingFillableMakerAssetAmounts.length',
+ );
+ assert.assert(
+ signedOrders.length === remainingFillableMakerAssetAmounts.length,
+ 'Expected signedFeeOrders.length to equal remainingFillableFeeAmounts.length',
+ );
+ // calculate total amount of ZRX needed to fill signedOrders
+ const totalFeeAmount = _.reduce(
+ signedOrders,
+ (accFees, order, index) => {
+ const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index];
+ const feeToFillMakerAssetAmountAvailable = makerAssetAmountAvailable
+ .mul(order.takerFee)
+ .div(order.makerAssetAmount);
+ return accFees.plus(feeToFillMakerAssetAmountAvailable);
+ },
+ constants.ZERO_AMOUNT,
+ );
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ signedFeeOrders,
+ remainingFillableFeeAmounts,
+ totalFeeAmount,
+ slippageBufferAmount,
+ );
+ return {
+ resultOrders,
+ remainingFeeAmount: remainingFillAmount,
+ };
+ // TODO: add more orders here to cover rounding
+ // https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarding-contract-specification.md#over-buying-zrx
+ },
+};