aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-utils/test
diff options
context:
space:
mode:
Diffstat (limited to 'packages/order-utils/test')
-rw-r--r--packages/order-utils/test/market_utils_test.ts280
-rw-r--r--packages/order-utils/test/utils/test_order_factory.ts32
2 files changed, 312 insertions, 0 deletions
diff --git a/packages/order-utils/test/market_utils_test.ts b/packages/order-utils/test/market_utils_test.ts
new file mode 100644
index 000000000..21c0a4802
--- /dev/null
+++ b/packages/order-utils/test/market_utils_test.ts
@@ -0,0 +1,280 @@
+import { BigNumber } from '@0xproject/utils';
+import * as chai from 'chai';
+import 'mocha';
+
+import { constants, marketUtils } from '../src';
+
+import { chaiSetup } from './utils/chai_setup';
+import { testOrderFactory } from './utils/test_order_factory';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+// tslint:disable: no-unused-expression
+describe('marketUtils', () => {
+ describe('#findOrdersThatCoverMakerAssetFillAmount', () => {
+ describe('no orders', () => {
+ it('returns empty and unchanged remainingFillAmount', async () => {
+ const fillAmount = new BigNumber(10);
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ [],
+ [],
+ fillAmount,
+ );
+ expect(resultOrders).to.be.empty;
+ expect(remainingFillAmount).to.be.bignumber.equal(fillAmount);
+ });
+ });
+ describe('orders are completely fillable', () => {
+ // generate three signed orders each with 10 units of makerAsset, 30 total
+ const makerAssetAmount = new BigNumber(10);
+ const inputOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ },
+ 3,
+ );
+ // generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
+ const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
+ it('returns input orders and zero remainingFillAmount when input exactly matches requested fill amount', async () => {
+ // try to fill 20 units of makerAsset
+ // include 10 units of slippageBufferAmount
+ const fillAmount = new BigNumber(20);
+ const slippageBufferAmount = new BigNumber(10);
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ fillAmount,
+ slippageBufferAmount,
+ );
+ expect(resultOrders).to.be.deep.equal(inputOrders);
+ expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('returns input orders and zero remainingFillAmount when input has more than requested fill amount', async () => {
+ // try to fill 15 units of makerAsset
+ // include 10 units of slippageBufferAmount
+ const fillAmount = new BigNumber(15);
+ const slippageBufferAmount = new BigNumber(10);
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ fillAmount,
+ slippageBufferAmount,
+ );
+ expect(resultOrders).to.be.deep.equal(inputOrders);
+ expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('returns input orders and non-zero remainingFillAmount when input has less than requested fill amount', async () => {
+ // try to fill 30 units of makerAsset
+ // include 5 units of slippageBufferAmount
+ const fillAmount = new BigNumber(30);
+ const slippageBufferAmount = new BigNumber(5);
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ fillAmount,
+ slippageBufferAmount,
+ );
+ expect(resultOrders).to.be.deep.equal(inputOrders);
+ expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(5));
+ });
+ it('returns first order and zero remainingFillAmount when requested fill amount is exactly covered by the first order', async () => {
+ // try to fill 10 units of makerAsset
+ const fillAmount = new BigNumber(10);
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ fillAmount,
+ );
+ expect(resultOrders).to.be.deep.equal([inputOrders[0]]);
+ expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ it('returns first two orders and zero remainingFillAmount when requested fill amount is over covered by the first two order', async () => {
+ // try to fill 15 units of makerAsset
+ const fillAmount = new BigNumber(15);
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ fillAmount,
+ );
+ expect(resultOrders).to.be.deep.equal([inputOrders[0], inputOrders[1]]);
+ expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ });
+ describe('orders are partially fillable', () => {
+ // generate three signed orders each with 10 units of makerAsset, 30 total
+ const makerAssetAmount = new BigNumber(10);
+ const inputOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ },
+ 3,
+ );
+ // generate remainingFillableMakerAssetAmounts that cover different partial fill scenarios
+ // 1. order is completely filled already
+ // 2. order is partially fillable
+ // 3. order is completely fillable
+ const remainingFillableMakerAssetAmounts = [constants.ZERO_AMOUNT, new BigNumber(5), makerAssetAmount];
+ it('returns last two orders and non-zero remainingFillAmount when trying to fill original makerAssetAmounts', async () => {
+ // try to fill 30 units of makerAsset
+ const fillAmount = new BigNumber(30);
+ const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ fillAmount,
+ );
+ expect(resultOrders).to.be.deep.equal([inputOrders[1], inputOrders[2]]);
+ expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(15));
+ });
+ });
+ });
+ describe('#findFeeOrdersThatCoverFeesForTargetOrders', () => {
+ // generate three signed fee orders each with 10 units of ZRX, 30 total
+ const zrxAmount = new BigNumber(10);
+ const inputFeeOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount: zrxAmount,
+ },
+ 3,
+ );
+ // generate remainingFillableFeeAmounts that equal the zrxAmount
+ const remainingFillableFeeAmounts = [zrxAmount, zrxAmount, zrxAmount];
+ describe('no target orders', () => {
+ it('returns empty and zero remainingFeeAmount', async () => {
+ const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
+ [],
+ [],
+ inputFeeOrders,
+ remainingFillableFeeAmounts,
+ );
+ expect(resultOrders).to.be.empty;
+ expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ });
+ describe('no fee orders', () => {
+ // generate three signed orders each with 10 units of makerAsset, 30 total
+ // each signed order requires 10 units of takerFee
+ const makerAssetAmount = new BigNumber(10);
+ const takerFee = new BigNumber(10);
+ const inputOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerFee,
+ },
+ 3,
+ );
+ // generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
+ const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
+ it('returns empty and non-zero remainingFeeAmount', async () => {
+ const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ [],
+ [],
+ );
+ expect(resultOrders).to.be.empty;
+ expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30));
+ });
+ });
+ describe('target orders have no fees', () => {
+ // generate three signed orders each with 10 units of makerAsset, 30 total
+ const makerAssetAmount = new BigNumber(10);
+ const inputOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ },
+ 3,
+ );
+ // generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
+ const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
+ it('returns empty and zero remainingFeeAmount', async () => {
+ const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ inputFeeOrders,
+ remainingFillableFeeAmounts,
+ );
+ expect(resultOrders).to.be.empty;
+ expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ });
+ describe('target orders require fees and are completely fillable', () => {
+ // generate three signed orders each with 10 units of makerAsset, 30 total
+ // each signed order requires 10 units of takerFee
+ const makerAssetAmount = new BigNumber(10);
+ const takerFee = new BigNumber(10);
+ const inputOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerFee,
+ },
+ 3,
+ );
+ // generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
+ const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
+ it('returns input fee orders and zero remainingFeeAmount', async () => {
+ const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ inputFeeOrders,
+ remainingFillableFeeAmounts,
+ );
+ expect(resultOrders).to.be.deep.equal(inputFeeOrders);
+ expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ });
+ describe('target orders require fees and are partially fillable', () => {
+ // generate three signed orders each with 10 units of makerAsset, 30 total
+ // each signed order requires 10 units of takerFee
+ const makerAssetAmount = new BigNumber(10);
+ const takerFee = new BigNumber(10);
+ const inputOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerFee,
+ },
+ 3,
+ );
+ // generate remainingFillableMakerAssetAmounts that cover different partial fill scenarios
+ // 1. order is completely filled already
+ // 2. order is partially fillable
+ // 3. order is completely fillable
+ const remainingFillableMakerAssetAmounts = [constants.ZERO_AMOUNT, new BigNumber(5), makerAssetAmount];
+ it('returns first two input fee orders and zero remainingFeeAmount', async () => {
+ const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ inputFeeOrders,
+ remainingFillableFeeAmounts,
+ );
+ expect(resultOrders).to.be.deep.equal([inputFeeOrders[0], inputFeeOrders[1]]);
+ expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
+ });
+ });
+ describe('target orders require more fees than available', () => {
+ // generate three signed orders each with 10 units of makerAsset, 30 total
+ // each signed order requires 20 units of takerFee
+ const makerAssetAmount = new BigNumber(10);
+ const takerFee = new BigNumber(20);
+ const inputOrders = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerFee,
+ },
+ 3,
+ );
+ // generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
+ const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
+ it('returns input fee orders and non-zero remainingFeeAmount', async () => {
+ const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
+ inputOrders,
+ remainingFillableMakerAssetAmounts,
+ inputFeeOrders,
+ remainingFillableFeeAmounts,
+ );
+ expect(resultOrders).to.be.deep.equal(inputFeeOrders);
+ expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30));
+ });
+ });
+ });
+});
diff --git a/packages/order-utils/test/utils/test_order_factory.ts b/packages/order-utils/test/utils/test_order_factory.ts
new file mode 100644
index 000000000..75dc6f1f2
--- /dev/null
+++ b/packages/order-utils/test/utils/test_order_factory.ts
@@ -0,0 +1,32 @@
+import { Order, SignedOrder } from '@0xproject/types';
+import * as _ from 'lodash';
+
+import { constants, orderFactory } from '../../src';
+
+const BASE_TEST_ORDER: Order = orderFactory.createOrder(
+ constants.NULL_ADDRESS,
+ constants.ZERO_AMOUNT,
+ constants.NULL_ADDRESS,
+ constants.ZERO_AMOUNT,
+ constants.NULL_ADDRESS,
+ constants.NULL_ADDRESS,
+);
+const BASE_TEST_SIGNED_ORDER: SignedOrder = {
+ ...BASE_TEST_ORDER,
+ signature: constants.NULL_BYTES,
+};
+
+export const testOrderFactory = {
+ generateTestSignedOrder(partialOrder: Partial<SignedOrder>): SignedOrder {
+ return transformObject(BASE_TEST_SIGNED_ORDER, partialOrder);
+ },
+ generateTestSignedOrders(partialOrder: Partial<SignedOrder>, numOrders: number): SignedOrder[] {
+ const baseTestOrders = _.map(_.range(numOrders), () => BASE_TEST_SIGNED_ORDER);
+ return _.map(baseTestOrders, order => transformObject(order, partialOrder));
+ },
+};
+
+function transformObject<T>(input: T, transformation: Partial<T>): T {
+ const copy = _.cloneDeep(input);
+ return _.assign(copy, transformation);
+}